agent-markdown-pdf 0.1.2__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/PKG-INFO +93 -7
  2. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/README.md +92 -6
  3. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/PKG-INFO +93 -7
  4. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/SOURCES.txt +1 -0
  5. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/api.py +4 -0
  6. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/doctor.py +110 -2
  7. agent_markdown_pdf-0.2.1/mdtopdf/core/fonts.py +456 -0
  8. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/html.py +4 -0
  9. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/markdown.py +88 -3
  10. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/mermaid.py +1 -1
  11. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/pdf.py +4 -0
  12. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/mdtopdf_cli.py +10 -0
  13. agent_markdown_pdf-0.2.1/mdtopdf/skills/SKILL.md +103 -0
  14. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/themes/default.css +31 -7
  15. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/pyproject.toml +1 -1
  16. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/tests/test_core.py +270 -0
  17. agent_markdown_pdf-0.1.2/mdtopdf/skills/SKILL.md +0 -84
  18. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/LICENSE +0 -0
  19. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/dependency_links.txt +0 -0
  20. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/entry_points.txt +0 -0
  21. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/requires.txt +0 -0
  22. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/top_level.txt +0 -0
  23. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/__init__.py +0 -0
  24. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/__main__.py +0 -0
  25. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/__init__.py +0 -0
  26. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/inline.py +0 -0
  27. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/katex.py +0 -0
  28. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/core/obsidian.py +0 -0
  29. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/LICENSE +0 -0
  30. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/contrib/mhchem.min.js +0 -0
  31. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  32. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  33. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  34. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  35. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  36. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  37. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  38. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  39. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  40. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  41. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  42. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  43. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  44. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  45. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  46. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  47. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  48. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  49. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  50. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  51. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  52. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  53. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  54. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  55. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  56. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  57. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  58. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  59. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  60. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  61. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  62. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  63. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  64. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  65. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  66. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  67. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  68. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  69. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  70. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  71. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  72. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  73. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  74. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  75. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  76. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  77. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  78. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  79. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  80. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  81. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  82. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  83. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  84. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  85. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  86. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  87. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  88. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  89. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  90. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  91. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/katex.min.css +0 -0
  92. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/katex.min.js +0 -0
  93. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/setup.cfg +0 -0
  94. {agent_markdown_pdf-0.1.2 → agent_markdown_pdf-0.2.1}/tests/test_full_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-markdown-pdf
3
- Version: 0.1.2
3
+ Version: 0.2.1
4
4
  Summary: Agent-friendly Markdown-to-PDF CLI with HTML preview and JSON diagnostics
5
5
  Author: rainp
6
6
  License-Expression: MIT
@@ -140,10 +140,10 @@ mdtopdf html report.md -o report.html --overwrite --json
140
140
  mdtopdf convert report.md -o report.pdf --overwrite --json
141
141
  ```
142
142
 
143
- `convert --json` returns the input path, output path, file size, theme, and
144
- render method. If conversion fails in JSON mode, the error is structured enough
145
- for an agent to show the command, explain the likely cause, and retry after a
146
- fix.
143
+ `convert --json` returns the input path, output path, file size, theme, font
144
+ check summary, warnings, and render method. If conversion fails in JSON mode,
145
+ the error is structured enough for an agent to show the command, explain the
146
+ likely cause, and retry after a fix.
147
147
 
148
148
  ## Visual output
149
149
 
@@ -175,7 +175,7 @@ remain visible as highlighted code.
175
175
  | Feature | Notes |
176
176
  | --- | --- |
177
177
  | JSON output | `--json` is available for conversion, HTML preview, doctor, and theme listing. |
178
- | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, and Mermaid availability. |
178
+ | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, Mermaid availability, and recommended fonts. |
179
179
  | Local rendering | Markdown, CSS, math, Mermaid SVG generation, and PDF export stay on the machine. |
180
180
  | HTML preview | Generate standalone HTML before PDF export for fast visual inspection. |
181
181
  | Obsidian compatibility | Wikilinks, aliases, frontmatter hiding, comments, highlights, and typed callouts. |
@@ -215,6 +215,38 @@ mdtopdf convert report.md -o report.pdf --base-url assets
215
215
  mdtopdf convert report.md -o report.pdf --resource-dir attachments
216
216
  ```
217
217
 
218
+ Custom CSS is the style extension point. Put document-specific rules in a CSS
219
+ file; fonts, spacing, colors, page rules, and code block styling all live there.
220
+ Use a system-installed font directly, or define `@font-face` for a local font
221
+ file. Relative URLs in CSS are resolved from the Markdown file's base URL, so
222
+ use `--base-url` when those assets live next to your document:
223
+
224
+ ```css
225
+ @font-face {
226
+ font-family: "Report Sans";
227
+ src: url("fonts/NotoSansSC-Regular.otf");
228
+ }
229
+
230
+ :root {
231
+ font-family: "Report Sans", "Noto Sans SC", "Source Han Sans SC", sans-serif;
232
+ }
233
+
234
+ code,
235
+ pre {
236
+ font-family: "Cascadia Code", "Liberation Mono", monospace;
237
+ }
238
+ ```
239
+
240
+ Then pass the CSS file:
241
+
242
+ ```shell
243
+ mdtopdf convert report.md -o report.pdf --css print.css --base-url .
244
+ ```
245
+
246
+ During export, `mdtopdf` checks the final CSS font stacks. Missing fonts do not
247
+ stop PDF generation, but they are reported in CLI warnings and in the JSON
248
+ `warnings` field.
249
+
218
250
  Return JSON:
219
251
 
220
252
  ```shell
@@ -291,6 +323,53 @@ rendering is available.
291
323
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
292
324
  and macOS package managers usually provide them through system packages.
293
325
 
326
+ The default theme uses a PDFium-safe Latin-first font stack. Latin fonts are
327
+ listed before CJK fonts so ASCII digits, dates, versions, and page numbers are
328
+ not embedded into CJK font subsets that some Chrome/PDFium renderers handle
329
+ poorly. Chinese text still falls back to the CJK side of the stack, where
330
+ `Microsoft YaHei` is the first preferred CJK font. If it is missing, the theme
331
+ falls back to `PingFang SC`, `Noto Sans SC`, `Noto Sans CJK SC`,
332
+ `Source Han Sans SC`, and other available CJK fonts.
333
+
334
+ For Linux containers or agent sandboxes, install fontconfig plus the fonts you
335
+ expect the default theme to use. A practical open-font baseline is:
336
+
337
+ ```shell
338
+ sudo apt-get install -y --no-install-recommends \
339
+ fontconfig \
340
+ fonts-noto-cjk \
341
+ fonts-liberation \
342
+ fonts-dejavu-core
343
+ fc-cache -f
344
+ ```
345
+
346
+ This baseline is a fallback. If you want Linux Chinese typography to match the
347
+ default Windows output more closely, provide `Microsoft YaHei` in the runtime
348
+ under your own font license. `mdtopdf` names that font in CSS but does not
349
+ bundle or download Microsoft font files. Providing Microsoft YaHei improves the
350
+ Chinese fallback; the Latin-first order is still kept for PDFium-safe digits.
351
+
352
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
353
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
354
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
355
+ Cascadia Code yourself or let the theme fall back to the installed monospace
356
+ fonts.
357
+
358
+ Emoji are rendered through the system emoji font. The default theme prefers
359
+ `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
360
+ usually provides it; Linux containers only get the same glyphs if the runtime
361
+ provides that font. If Segoe UI Emoji is not available, the theme falls back to
362
+ `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
363
+ fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
364
+ Pango/Cairo, and the PDF viewer.
365
+
366
+ Optional fallback fonts:
367
+
368
+ ```shell
369
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
370
+ fc-cache -f
371
+ ```
372
+
294
373
  On Windows, install the native libraries separately. A common MSYS2 setup is:
295
374
 
296
375
  ```powershell
@@ -310,7 +389,8 @@ if MSYS2 is installed somewhere else:
310
389
  setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
311
390
  ```
312
391
 
313
- Run this after installation:
392
+ Run this after installation. The JSON output also reports whether recommended
393
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
314
394
 
315
395
  ```shell
316
396
  mdtopdf doctor --json
@@ -336,3 +416,9 @@ python -m twine check dist/*
336
416
 
337
417
  MIT. Bundled KaTeX assets are also distributed under the MIT license; see
338
418
  `mdtopdf/vendor/katex/LICENSE`.
419
+
420
+ `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
421
+ fonts. The default theme references local system fonts such as Segoe UI,
422
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Emoji, Noto Color Emoji,
423
+ Cascadia Code, and Consolas, but those font files come from the user's operating
424
+ system or runtime environment.
@@ -99,10 +99,10 @@ mdtopdf html report.md -o report.html --overwrite --json
99
99
  mdtopdf convert report.md -o report.pdf --overwrite --json
100
100
  ```
101
101
 
102
- `convert --json` returns the input path, output path, file size, theme, and
103
- render method. If conversion fails in JSON mode, the error is structured enough
104
- for an agent to show the command, explain the likely cause, and retry after a
105
- fix.
102
+ `convert --json` returns the input path, output path, file size, theme, font
103
+ check summary, warnings, and render method. If conversion fails in JSON mode,
104
+ the error is structured enough for an agent to show the command, explain the
105
+ likely cause, and retry after a fix.
106
106
 
107
107
  ## Visual output
108
108
 
@@ -134,7 +134,7 @@ remain visible as highlighted code.
134
134
  | Feature | Notes |
135
135
  | --- | --- |
136
136
  | JSON output | `--json` is available for conversion, HTML preview, doctor, and theme listing. |
137
- | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, and Mermaid availability. |
137
+ | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, Mermaid availability, and recommended fonts. |
138
138
  | Local rendering | Markdown, CSS, math, Mermaid SVG generation, and PDF export stay on the machine. |
139
139
  | HTML preview | Generate standalone HTML before PDF export for fast visual inspection. |
140
140
  | Obsidian compatibility | Wikilinks, aliases, frontmatter hiding, comments, highlights, and typed callouts. |
@@ -174,6 +174,38 @@ mdtopdf convert report.md -o report.pdf --base-url assets
174
174
  mdtopdf convert report.md -o report.pdf --resource-dir attachments
175
175
  ```
176
176
 
177
+ Custom CSS is the style extension point. Put document-specific rules in a CSS
178
+ file; fonts, spacing, colors, page rules, and code block styling all live there.
179
+ Use a system-installed font directly, or define `@font-face` for a local font
180
+ file. Relative URLs in CSS are resolved from the Markdown file's base URL, so
181
+ use `--base-url` when those assets live next to your document:
182
+
183
+ ```css
184
+ @font-face {
185
+ font-family: "Report Sans";
186
+ src: url("fonts/NotoSansSC-Regular.otf");
187
+ }
188
+
189
+ :root {
190
+ font-family: "Report Sans", "Noto Sans SC", "Source Han Sans SC", sans-serif;
191
+ }
192
+
193
+ code,
194
+ pre {
195
+ font-family: "Cascadia Code", "Liberation Mono", monospace;
196
+ }
197
+ ```
198
+
199
+ Then pass the CSS file:
200
+
201
+ ```shell
202
+ mdtopdf convert report.md -o report.pdf --css print.css --base-url .
203
+ ```
204
+
205
+ During export, `mdtopdf` checks the final CSS font stacks. Missing fonts do not
206
+ stop PDF generation, but they are reported in CLI warnings and in the JSON
207
+ `warnings` field.
208
+
177
209
  Return JSON:
178
210
 
179
211
  ```shell
@@ -250,6 +282,53 @@ rendering is available.
250
282
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
251
283
  and macOS package managers usually provide them through system packages.
252
284
 
285
+ The default theme uses a PDFium-safe Latin-first font stack. Latin fonts are
286
+ listed before CJK fonts so ASCII digits, dates, versions, and page numbers are
287
+ not embedded into CJK font subsets that some Chrome/PDFium renderers handle
288
+ poorly. Chinese text still falls back to the CJK side of the stack, where
289
+ `Microsoft YaHei` is the first preferred CJK font. If it is missing, the theme
290
+ falls back to `PingFang SC`, `Noto Sans SC`, `Noto Sans CJK SC`,
291
+ `Source Han Sans SC`, and other available CJK fonts.
292
+
293
+ For Linux containers or agent sandboxes, install fontconfig plus the fonts you
294
+ expect the default theme to use. A practical open-font baseline is:
295
+
296
+ ```shell
297
+ sudo apt-get install -y --no-install-recommends \
298
+ fontconfig \
299
+ fonts-noto-cjk \
300
+ fonts-liberation \
301
+ fonts-dejavu-core
302
+ fc-cache -f
303
+ ```
304
+
305
+ This baseline is a fallback. If you want Linux Chinese typography to match the
306
+ default Windows output more closely, provide `Microsoft YaHei` in the runtime
307
+ under your own font license. `mdtopdf` names that font in CSS but does not
308
+ bundle or download Microsoft font files. Providing Microsoft YaHei improves the
309
+ Chinese fallback; the Latin-first order is still kept for PDFium-safe digits.
310
+
311
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
312
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
313
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
314
+ Cascadia Code yourself or let the theme fall back to the installed monospace
315
+ fonts.
316
+
317
+ Emoji are rendered through the system emoji font. The default theme prefers
318
+ `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
319
+ usually provides it; Linux containers only get the same glyphs if the runtime
320
+ provides that font. If Segoe UI Emoji is not available, the theme falls back to
321
+ `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
322
+ fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
323
+ Pango/Cairo, and the PDF viewer.
324
+
325
+ Optional fallback fonts:
326
+
327
+ ```shell
328
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
329
+ fc-cache -f
330
+ ```
331
+
253
332
  On Windows, install the native libraries separately. A common MSYS2 setup is:
254
333
 
255
334
  ```powershell
@@ -269,7 +348,8 @@ if MSYS2 is installed somewhere else:
269
348
  setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
270
349
  ```
271
350
 
272
- Run this after installation:
351
+ Run this after installation. The JSON output also reports whether recommended
352
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
273
353
 
274
354
  ```shell
275
355
  mdtopdf doctor --json
@@ -295,3 +375,9 @@ python -m twine check dist/*
295
375
 
296
376
  MIT. Bundled KaTeX assets are also distributed under the MIT license; see
297
377
  `mdtopdf/vendor/katex/LICENSE`.
378
+
379
+ `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
380
+ fonts. The default theme references local system fonts such as Segoe UI,
381
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Emoji, Noto Color Emoji,
382
+ Cascadia Code, and Consolas, but those font files come from the user's operating
383
+ system or runtime environment.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-markdown-pdf
3
- Version: 0.1.2
3
+ Version: 0.2.1
4
4
  Summary: Agent-friendly Markdown-to-PDF CLI with HTML preview and JSON diagnostics
5
5
  Author: rainp
6
6
  License-Expression: MIT
@@ -140,10 +140,10 @@ mdtopdf html report.md -o report.html --overwrite --json
140
140
  mdtopdf convert report.md -o report.pdf --overwrite --json
141
141
  ```
142
142
 
143
- `convert --json` returns the input path, output path, file size, theme, and
144
- render method. If conversion fails in JSON mode, the error is structured enough
145
- for an agent to show the command, explain the likely cause, and retry after a
146
- fix.
143
+ `convert --json` returns the input path, output path, file size, theme, font
144
+ check summary, warnings, and render method. If conversion fails in JSON mode,
145
+ the error is structured enough for an agent to show the command, explain the
146
+ likely cause, and retry after a fix.
147
147
 
148
148
  ## Visual output
149
149
 
@@ -175,7 +175,7 @@ remain visible as highlighted code.
175
175
  | Feature | Notes |
176
176
  | --- | --- |
177
177
  | JSON output | `--json` is available for conversion, HTML preview, doctor, and theme listing. |
178
- | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, and Mermaid availability. |
178
+ | Environment checks | `doctor --json` checks Python imports, native WeasyPrint libraries, Windows DLL paths, Mermaid availability, and recommended fonts. |
179
179
  | Local rendering | Markdown, CSS, math, Mermaid SVG generation, and PDF export stay on the machine. |
180
180
  | HTML preview | Generate standalone HTML before PDF export for fast visual inspection. |
181
181
  | Obsidian compatibility | Wikilinks, aliases, frontmatter hiding, comments, highlights, and typed callouts. |
@@ -215,6 +215,38 @@ mdtopdf convert report.md -o report.pdf --base-url assets
215
215
  mdtopdf convert report.md -o report.pdf --resource-dir attachments
216
216
  ```
217
217
 
218
+ Custom CSS is the style extension point. Put document-specific rules in a CSS
219
+ file; fonts, spacing, colors, page rules, and code block styling all live there.
220
+ Use a system-installed font directly, or define `@font-face` for a local font
221
+ file. Relative URLs in CSS are resolved from the Markdown file's base URL, so
222
+ use `--base-url` when those assets live next to your document:
223
+
224
+ ```css
225
+ @font-face {
226
+ font-family: "Report Sans";
227
+ src: url("fonts/NotoSansSC-Regular.otf");
228
+ }
229
+
230
+ :root {
231
+ font-family: "Report Sans", "Noto Sans SC", "Source Han Sans SC", sans-serif;
232
+ }
233
+
234
+ code,
235
+ pre {
236
+ font-family: "Cascadia Code", "Liberation Mono", monospace;
237
+ }
238
+ ```
239
+
240
+ Then pass the CSS file:
241
+
242
+ ```shell
243
+ mdtopdf convert report.md -o report.pdf --css print.css --base-url .
244
+ ```
245
+
246
+ During export, `mdtopdf` checks the final CSS font stacks. Missing fonts do not
247
+ stop PDF generation, but they are reported in CLI warnings and in the JSON
248
+ `warnings` field.
249
+
218
250
  Return JSON:
219
251
 
220
252
  ```shell
@@ -291,6 +323,53 @@ rendering is available.
291
323
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
292
324
  and macOS package managers usually provide them through system packages.
293
325
 
326
+ The default theme uses a PDFium-safe Latin-first font stack. Latin fonts are
327
+ listed before CJK fonts so ASCII digits, dates, versions, and page numbers are
328
+ not embedded into CJK font subsets that some Chrome/PDFium renderers handle
329
+ poorly. Chinese text still falls back to the CJK side of the stack, where
330
+ `Microsoft YaHei` is the first preferred CJK font. If it is missing, the theme
331
+ falls back to `PingFang SC`, `Noto Sans SC`, `Noto Sans CJK SC`,
332
+ `Source Han Sans SC`, and other available CJK fonts.
333
+
334
+ For Linux containers or agent sandboxes, install fontconfig plus the fonts you
335
+ expect the default theme to use. A practical open-font baseline is:
336
+
337
+ ```shell
338
+ sudo apt-get install -y --no-install-recommends \
339
+ fontconfig \
340
+ fonts-noto-cjk \
341
+ fonts-liberation \
342
+ fonts-dejavu-core
343
+ fc-cache -f
344
+ ```
345
+
346
+ This baseline is a fallback. If you want Linux Chinese typography to match the
347
+ default Windows output more closely, provide `Microsoft YaHei` in the runtime
348
+ under your own font license. `mdtopdf` names that font in CSS but does not
349
+ bundle or download Microsoft font files. Providing Microsoft YaHei improves the
350
+ Chinese fallback; the Latin-first order is still kept for PDFium-safe digits.
351
+
352
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
353
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
354
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
355
+ Cascadia Code yourself or let the theme fall back to the installed monospace
356
+ fonts.
357
+
358
+ Emoji are rendered through the system emoji font. The default theme prefers
359
+ `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
360
+ usually provides it; Linux containers only get the same glyphs if the runtime
361
+ provides that font. If Segoe UI Emoji is not available, the theme falls back to
362
+ `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
363
+ fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
364
+ Pango/Cairo, and the PDF viewer.
365
+
366
+ Optional fallback fonts:
367
+
368
+ ```shell
369
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
370
+ fc-cache -f
371
+ ```
372
+
294
373
  On Windows, install the native libraries separately. A common MSYS2 setup is:
295
374
 
296
375
  ```powershell
@@ -310,7 +389,8 @@ if MSYS2 is installed somewhere else:
310
389
  setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
311
390
  ```
312
391
 
313
- Run this after installation:
392
+ Run this after installation. The JSON output also reports whether recommended
393
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
314
394
 
315
395
  ```shell
316
396
  mdtopdf doctor --json
@@ -336,3 +416,9 @@ python -m twine check dist/*
336
416
 
337
417
  MIT. Bundled KaTeX assets are also distributed under the MIT license; see
338
418
  `mdtopdf/vendor/katex/LICENSE`.
419
+
420
+ `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
421
+ fonts. The default theme references local system fonts such as Segoe UI,
422
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Emoji, Noto Color Emoji,
423
+ Cascadia Code, and Consolas, but those font files come from the user's operating
424
+ system or runtime environment.
@@ -13,6 +13,7 @@ mdtopdf/api.py
13
13
  mdtopdf/mdtopdf_cli.py
14
14
  mdtopdf/core/__init__.py
15
15
  mdtopdf/core/doctor.py
16
+ mdtopdf/core/fonts.py
16
17
  mdtopdf/core/html.py
17
18
  mdtopdf/core/inline.py
18
19
  mdtopdf/core/katex.py
@@ -13,6 +13,7 @@ from typing import Any
13
13
  from urllib.parse import urlparse
14
14
 
15
15
  from mdtopdf.core.doctor import add_weasyprint_dll_directories
16
+ from mdtopdf.core.fonts import inspect_css_font_usage, summarize_font_usage
16
17
  from mdtopdf.core.html import convert_markdown_file_to_html
17
18
  from mdtopdf.core.markdown import DEFAULT_THEME, RenderedHTML, render_markdown_to_html
18
19
  from mdtopdf.core.obsidian import build_resource_resolver, resolve_resource_dir
@@ -143,6 +144,7 @@ def markdown_to_pdf(
143
144
  include_page_footer=include_page_footer,
144
145
  page_numbers=page_numbers,
145
146
  )
147
+ font_usage = inspect_css_font_usage(rendered.css, document_text=markdown_text)
146
148
 
147
149
  output.parent.mkdir(parents=True, exist_ok=True)
148
150
  try:
@@ -174,6 +176,8 @@ def markdown_to_pdf(
174
176
  "page_header": effective_header,
175
177
  "page_footer": effective_footer,
176
178
  "page_numbers": bool(include_page_footer and page_numbers),
179
+ "font_check": summarize_font_usage(font_usage),
180
+ "warnings": font_usage.get("warnings", []),
177
181
  "method": "markdown-it-py+weasyprint",
178
182
  }
179
183
 
@@ -4,10 +4,13 @@ import ctypes
4
4
  import importlib
5
5
  import os
6
6
  import platform
7
+ import shutil
8
+ import subprocess
7
9
  import sys
8
10
  from pathlib import Path
9
11
  from typing import Any
10
12
 
13
+ from mdtopdf.core.fonts import inspect_recommended_font_groups
11
14
  from mdtopdf.core.mermaid import inspect_mermaid_backend
12
15
 
13
16
 
@@ -21,8 +24,6 @@ COMMON_WINDOWS_DLL_DIRS = (
21
24
  r"C:\msys64\mingw64\bin",
22
25
  r"D:\Environment\msys64\mingw64\bin",
23
26
  )
24
-
25
-
26
27
  def add_weasyprint_dll_directories() -> list[str]:
27
28
  """Register Windows DLL search directories from ``WEASYPRINT_DLL_DIRECTORIES``."""
28
29
 
@@ -68,6 +69,7 @@ def run_doctor() -> dict[str, Any]:
68
69
  "packages": {},
69
70
  "tools": {},
70
71
  "native_libraries": _inspect_native_libraries(),
72
+ "fonts": _inspect_fonts(),
71
73
  "recommendations": [],
72
74
  }
73
75
 
@@ -76,6 +78,8 @@ def run_doctor() -> dict[str, Any]:
76
78
  result["packages"]["latex2mathml"] = _check_python_package("latex2mathml")
77
79
  result["packages"]["matplotlib"] = _check_python_package("matplotlib")
78
80
  result["tools"]["mermaid"] = inspect_mermaid_backend()
81
+ if result["platform"]["system"] == "Linux":
82
+ result["tools"]["fontconfig"] = _inspect_fontconfig()
79
83
  result["ok"] = all(info["ok"] for info in result["packages"].values())
80
84
  result["recommendations"] = _recommendations(result)
81
85
  return result
@@ -115,6 +119,19 @@ def format_doctor_text(result: dict[str, Any]) -> str:
115
119
  f"missing={', '.join(probe['missing']) or '(none)'}"
116
120
  )
117
121
 
122
+ if result.get("fonts"):
123
+ lines.extend(["", "Fonts:"])
124
+ font_error = result["fonts"].get("error")
125
+ if font_error:
126
+ lines.append(f" - font inspection: FAIL - {font_error}")
127
+ for name, info in result["fonts"].get("groups", {}).items():
128
+ found = ", ".join(info.get("found", [])) or "(none)"
129
+ recommended = ", ".join(info.get("recommended", []))
130
+ lines.append(
131
+ f" - {name}: {'OK' if info.get('ok') else 'MISSING'} "
132
+ f"found={found} recommended={recommended}"
133
+ )
134
+
118
135
  if result.get("recommendations"):
119
136
  lines.extend(["", "Recommendations:"])
120
137
  for item in result["recommendations"]:
@@ -194,8 +211,42 @@ def _env_dll_directories() -> list[str]:
194
211
  return [part.strip() for part in raw.split(os.pathsep) if part.strip()]
195
212
 
196
213
 
214
+ def _inspect_fonts() -> dict[str, Any]:
215
+ return inspect_recommended_font_groups()
216
+
217
+
218
+ def _inspect_fontconfig() -> dict[str, Any]:
219
+ executable = shutil.which("fc-match")
220
+ result: dict[str, Any] = {
221
+ "ok": False,
222
+ "executable": executable,
223
+ "sample": None,
224
+ "error": None,
225
+ }
226
+ if not executable:
227
+ result["error"] = "fc-match was not found on PATH."
228
+ return result
229
+
230
+ try:
231
+ proc = subprocess.run(
232
+ [executable, "-f", "%{family}\n", "sans-serif"],
233
+ check=True,
234
+ capture_output=True,
235
+ text=True,
236
+ timeout=5,
237
+ )
238
+ except Exception as exc:
239
+ result["error"] = f"{type(exc).__name__}: {exc}"
240
+ return result
241
+
242
+ result["sample"] = proc.stdout.strip() or None
243
+ result["ok"] = True
244
+ return result
245
+
246
+
197
247
  def _recommendations(result: dict[str, Any]) -> list[str]:
198
248
  recommendations: list[str] = []
249
+ is_linux = result.get("platform", {}).get("system") == "Linux"
199
250
  package_info = result.get("packages", {}).get("weasyprint", {})
200
251
  if not package_info.get("ok"):
201
252
  recommendations.append("Install Python dependencies with: python -m pip install agent-markdown-pdf")
@@ -215,6 +266,63 @@ def _recommendations(result: dict[str, Any]) -> list[str]:
215
266
  "Optional: install Mermaid rendering support with Node.js plus: "
216
267
  "npm install -g @mermaid-js/mermaid-cli"
217
268
  )
269
+ fontconfig_info = result.get("tools", {}).get("fontconfig")
270
+ if is_linux and fontconfig_info and not fontconfig_info.get("ok"):
271
+ recommendations.append(
272
+ "Install fontconfig so WeasyPrint/Pango can resolve system fonts, for example: "
273
+ "sudo apt-get install fontconfig"
274
+ )
275
+
276
+ font_info = result.get("fonts", {})
277
+ font_groups = font_info.get("groups", {})
278
+ if font_info.get("error"):
279
+ recommendations.append("Font inspection failed; run conversion once and verify CJK text visually.")
280
+ if font_groups.get("latin_sans") and not font_groups["latin_sans"].get("ok"):
281
+ recommendations.append(
282
+ "Install a Latin sans font so digits, dates, versions, and page counters avoid CJK font subsets. "
283
+ "On Debian or Ubuntu, use: sudo apt-get install fonts-liberation fonts-dejavu-core"
284
+ )
285
+ if font_groups.get("cjk_sans") and not font_groups["cjk_sans"].get("ok"):
286
+ recommendations.append(
287
+ "Provide Microsoft YaHei in the runtime to match the default theme's Windows-like Chinese typography. "
288
+ "On Debian or Ubuntu, Noto CJK is a supported fallback: sudo apt-get install fonts-noto-cjk"
289
+ )
290
+ elif is_linux and font_groups.get("cjk_sans") and "Microsoft YaHei" in font_groups["cjk_sans"].get("missing", []):
291
+ recommendations.append(
292
+ "Optional: provide Microsoft YaHei in the Linux runtime to match the default theme's Windows-like "
293
+ "Chinese typography. Without it, output falls back to installed CJK fonts such as Noto CJK."
294
+ )
295
+ if font_groups.get("monospace") and not font_groups["monospace"].get("ok"):
296
+ recommendations.append(
297
+ "Install a monospace font for code blocks. On Debian or Ubuntu, use: "
298
+ "sudo apt-get install fonts-cascadia-code if that package is available; "
299
+ "otherwise provide Cascadia Code in the runtime."
300
+ )
301
+ elif (
302
+ is_linux
303
+ and font_groups.get("monospace")
304
+ and "Cascadia Mono" in font_groups["monospace"].get("missing", [])
305
+ and "Cascadia Code" in font_groups["monospace"].get("missing", [])
306
+ ):
307
+ recommendations.append(
308
+ "Optional: install Cascadia Code on Linux for default-theme code blocks: "
309
+ "sudo apt-get install fonts-cascadia-code if that package is available, "
310
+ "or provide Cascadia Code in the runtime."
311
+ )
312
+ if font_groups.get("math") and not font_groups["math"].get("ok"):
313
+ recommendations.append(
314
+ "Optional: install STIX fonts for math fallback, for example: sudo apt-get install fonts-stix"
315
+ )
316
+ if font_groups.get("emoji") and not font_groups["emoji"].get("ok"):
317
+ recommendations.append(
318
+ "Provide Segoe UI Emoji in the runtime if you want the default theme's first-choice "
319
+ "emoji glyphs. If that is not available, install another emoji font and run fc-cache -f."
320
+ )
321
+ elif font_groups.get("emoji") and "Segoe UI Emoji" in font_groups["emoji"].get("missing", []):
322
+ recommendations.append(
323
+ "Optional: provide Segoe UI Emoji if you want the default theme's preferred emoji glyphs. "
324
+ "Existing emoji fallback fonts will still be used."
325
+ )
218
326
 
219
327
  if os.name == "nt":
220
328
  env_value = result.get("environment", {}).get(WINDOWS_DLL_ENV)