agent-markdown-pdf 0.2.0__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.2.0 → agent_markdown_pdf-0.2.1}/PKG-INFO +38 -15
  2. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/README.md +37 -14
  3. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/PKG-INFO +38 -15
  4. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/doctor.py +66 -3
  5. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/fonts.py +21 -1
  6. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/markdown.py +7 -0
  7. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/mermaid.py +1 -1
  8. agent_markdown_pdf-0.2.1/mdtopdf/skills/SKILL.md +103 -0
  9. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/themes/default.css +3 -3
  10. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/pyproject.toml +1 -1
  11. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/tests/test_core.py +115 -2
  12. agent_markdown_pdf-0.2.0/mdtopdf/skills/SKILL.md +0 -108
  13. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/LICENSE +0 -0
  14. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/SOURCES.txt +0 -0
  15. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/dependency_links.txt +0 -0
  16. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/entry_points.txt +0 -0
  17. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/requires.txt +0 -0
  18. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/agent_markdown_pdf.egg-info/top_level.txt +0 -0
  19. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/__init__.py +0 -0
  20. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/__main__.py +0 -0
  21. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/api.py +0 -0
  22. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/__init__.py +0 -0
  23. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/html.py +0 -0
  24. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/inline.py +0 -0
  25. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/katex.py +0 -0
  26. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/obsidian.py +0 -0
  27. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/core/pdf.py +0 -0
  28. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/mdtopdf_cli.py +0 -0
  29. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/LICENSE +0 -0
  30. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/contrib/mhchem.min.js +0 -0
  31. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  32. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  33. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  34. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  35. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  36. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  37. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  38. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  39. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  40. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  41. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  42. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  43. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  44. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  45. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  46. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  47. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  48. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  49. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  50. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  51. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  52. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  53. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  54. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  55. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  56. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  57. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  58. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  59. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  60. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  61. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  62. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  63. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  64. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  65. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  66. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  67. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  68. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  69. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  70. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  71. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  72. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  73. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  74. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  75. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  76. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  77. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  78. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  79. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  80. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  81. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  82. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  83. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  84. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  85. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  86. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  87. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  88. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  89. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  90. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  91. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/katex.min.css +0 -0
  92. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/mdtopdf/vendor/katex/dist/katex.min.js +0 -0
  93. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.1}/setup.cfg +0 -0
  94. {agent_markdown_pdf-0.2.0 → 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.2.0
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
@@ -323,15 +323,37 @@ rendering is available.
323
323
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
324
324
  and macOS package managers usually provide them through system packages.
325
325
 
326
- The default theme names `Microsoft YaHei` first in its CSS on every platform,
327
- including Linux. If that font is installed in the environment, WeasyPrint will
328
- use it. If it is missing, the theme falls back to `PingFang SC`,
329
- `Noto Sans SC`, `Noto Sans CJK SC`, `Source Han Sans SC`, and other available
330
- CJK fonts.
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.
331
333
 
332
- For stable CJK output in Linux containers or agent sandboxes where Microsoft
333
- YaHei is not installed, install the CJK font you want to use. Noto CJK is a
334
- practical fallback on Debian or Ubuntu:
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.
335
357
 
336
358
  Emoji are rendered through the system emoji font. The default theme prefers
337
359
  `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
@@ -341,10 +363,10 @@ provides that font. If Segoe UI Emoji is not available, the theme falls back to
341
363
  fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
342
364
  Pango/Cairo, and the PDF viewer.
343
365
 
344
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
366
+ Optional fallback fonts:
345
367
 
346
368
  ```shell
347
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
369
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
348
370
  fc-cache -f
349
371
  ```
350
372
 
@@ -368,7 +390,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
368
390
  ```
369
391
 
370
392
  Run this after installation. The JSON output also reports whether recommended
371
- CJK, emoji, monospace, and math fallback fonts are present:
393
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
372
394
 
373
395
  ```shell
374
396
  mdtopdf doctor --json
@@ -396,6 +418,7 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
396
418
  `mdtopdf/vendor/katex/LICENSE`.
397
419
 
398
420
  `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
399
- fonts. The default theme references local system fonts such as Microsoft YaHei,
400
- PingFang SC, Segoe UI, Segoe UI Emoji, Noto Emoji, Noto Color Emoji, and Consolas, but
401
- those font files come from the user's operating system or runtime environment.
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.
@@ -282,15 +282,37 @@ rendering is available.
282
282
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
283
283
  and macOS package managers usually provide them through system packages.
284
284
 
285
- The default theme names `Microsoft YaHei` first in its CSS on every platform,
286
- including Linux. If that font is installed in the environment, WeasyPrint will
287
- use it. If it is missing, the theme falls back to `PingFang SC`,
288
- `Noto Sans SC`, `Noto Sans CJK SC`, `Source Han Sans SC`, and other available
289
- CJK fonts.
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.
290
292
 
291
- For stable CJK output in Linux containers or agent sandboxes where Microsoft
292
- YaHei is not installed, install the CJK font you want to use. Noto CJK is a
293
- practical fallback on Debian or Ubuntu:
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.
294
316
 
295
317
  Emoji are rendered through the system emoji font. The default theme prefers
296
318
  `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
@@ -300,10 +322,10 @@ provides that font. If Segoe UI Emoji is not available, the theme falls back to
300
322
  fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
301
323
  Pango/Cairo, and the PDF viewer.
302
324
 
303
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
325
+ Optional fallback fonts:
304
326
 
305
327
  ```shell
306
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
328
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
307
329
  fc-cache -f
308
330
  ```
309
331
 
@@ -327,7 +349,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
327
349
  ```
328
350
 
329
351
  Run this after installation. The JSON output also reports whether recommended
330
- CJK, emoji, monospace, and math fallback fonts are present:
352
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
331
353
 
332
354
  ```shell
333
355
  mdtopdf doctor --json
@@ -355,6 +377,7 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
355
377
  `mdtopdf/vendor/katex/LICENSE`.
356
378
 
357
379
  `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
358
- fonts. The default theme references local system fonts such as Microsoft YaHei,
359
- PingFang SC, Segoe UI, Segoe UI Emoji, Noto Emoji, Noto Color Emoji, and Consolas, but
360
- those font files come from the user's operating system or runtime environment.
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.2.0
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
@@ -323,15 +323,37 @@ rendering is available.
323
323
  WeasyPrint also needs native libraries such as Pango, GLib, and Cairo. Linux
324
324
  and macOS package managers usually provide them through system packages.
325
325
 
326
- The default theme names `Microsoft YaHei` first in its CSS on every platform,
327
- including Linux. If that font is installed in the environment, WeasyPrint will
328
- use it. If it is missing, the theme falls back to `PingFang SC`,
329
- `Noto Sans SC`, `Noto Sans CJK SC`, `Source Han Sans SC`, and other available
330
- CJK fonts.
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.
331
333
 
332
- For stable CJK output in Linux containers or agent sandboxes where Microsoft
333
- YaHei is not installed, install the CJK font you want to use. Noto CJK is a
334
- practical fallback on Debian or Ubuntu:
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.
335
357
 
336
358
  Emoji are rendered through the system emoji font. The default theme prefers
337
359
  `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
@@ -341,10 +363,10 @@ provides that font. If Segoe UI Emoji is not available, the theme falls back to
341
363
  fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
342
364
  Pango/Cairo, and the PDF viewer.
343
365
 
344
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
366
+ Optional fallback fonts:
345
367
 
346
368
  ```shell
347
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
369
+ sudo apt-get install -y --no-install-recommends fonts-noto-color-emoji fonts-stix
348
370
  fc-cache -f
349
371
  ```
350
372
 
@@ -368,7 +390,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
368
390
  ```
369
391
 
370
392
  Run this after installation. The JSON output also reports whether recommended
371
- CJK, emoji, monospace, and math fallback fonts are present:
393
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
372
394
 
373
395
  ```shell
374
396
  mdtopdf doctor --json
@@ -396,6 +418,7 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
396
418
  `mdtopdf/vendor/katex/LICENSE`.
397
419
 
398
420
  `mdtopdf` does not bundle CJK body fonts, emoji fonts, or proprietary system
399
- fonts. The default theme references local system fonts such as Microsoft YaHei,
400
- PingFang SC, Segoe UI, Segoe UI Emoji, Noto Emoji, Noto Color Emoji, and Consolas, but
401
- those font files come from the user's operating system or runtime environment.
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.
@@ -4,6 +4,8 @@ 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
@@ -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
@@ -211,8 +215,38 @@ def _inspect_fonts() -> dict[str, Any]:
211
215
  return inspect_recommended_font_groups()
212
216
 
213
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
+
214
247
  def _recommendations(result: dict[str, Any]) -> list[str]:
215
248
  recommendations: list[str] = []
249
+ is_linux = result.get("platform", {}).get("system") == "Linux"
216
250
  package_info = result.get("packages", {}).get("weasyprint", {})
217
251
  if not package_info.get("ok"):
218
252
  recommendations.append("Install Python dependencies with: python -m pip install agent-markdown-pdf")
@@ -232,19 +266,48 @@ def _recommendations(result: dict[str, Any]) -> list[str]:
232
266
  "Optional: install Mermaid rendering support with Node.js plus: "
233
267
  "npm install -g @mermaid-js/mermaid-cli"
234
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
+ )
235
275
 
236
276
  font_info = result.get("fonts", {})
237
277
  font_groups = font_info.get("groups", {})
238
278
  if font_info.get("error"):
239
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
+ )
240
285
  if font_groups.get("cjk_sans") and not font_groups["cjk_sans"].get("ok"):
241
286
  recommendations.append(
242
- "Install Microsoft YaHei when you want the default theme to match its first-choice CJK font. "
243
- "On Debian or Ubuntu, Noto CJK is a practical fallback: sudo apt-get install fonts-noto-cjk"
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."
244
294
  )
245
295
  if font_groups.get("monospace") and not font_groups["monospace"].get("ok"):
246
296
  recommendations.append(
247
- "Optional: install a monospace font such as Cascadia Code or Liberation Mono for stable code blocks."
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."
248
311
  )
249
312
  if font_groups.get("math") and not font_groups["math"].get("ok"):
250
313
  recommendations.append(
@@ -33,8 +33,19 @@ GENERIC_FONT_FAMILIES = {
33
33
  }
34
34
 
35
35
  RECOMMENDED_FONT_GROUPS = {
36
+ "latin_sans": {
37
+ "description": "Latin body text and digits",
38
+ "preferred": ("Segoe UI", "Arial", "Liberation Sans", "DejaVu Sans"),
39
+ "families": (
40
+ "Segoe UI",
41
+ "Arial",
42
+ "Liberation Sans",
43
+ "DejaVu Sans",
44
+ ),
45
+ },
36
46
  "cjk_sans": {
37
47
  "description": "CJK body text",
48
+ "preferred": ("Microsoft YaHei",),
38
49
  "families": (
39
50
  "Microsoft YaHei",
40
51
  "PingFang SC",
@@ -47,6 +58,7 @@ RECOMMENDED_FONT_GROUPS = {
47
58
  },
48
59
  "monospace": {
49
60
  "description": "Code blocks",
61
+ "preferred": ("Cascadia Mono", "Cascadia Code"),
50
62
  "families": (
51
63
  "Cascadia Mono",
52
64
  "Cascadia Code",
@@ -58,6 +70,7 @@ RECOMMENDED_FONT_GROUPS = {
58
70
  },
59
71
  "math": {
60
72
  "description": "Math fallback",
73
+ "preferred": ("Cambria Math",),
61
74
  "families": (
62
75
  "Cambria Math",
63
76
  "STIX Two Math",
@@ -67,6 +80,7 @@ RECOMMENDED_FONT_GROUPS = {
67
80
  },
68
81
  "emoji": {
69
82
  "description": "Emoji glyphs",
83
+ "preferred": ("Segoe UI Emoji",),
70
84
  "families": (
71
85
  "Segoe UI Emoji",
72
86
  "Apple Color Emoji",
@@ -115,6 +129,8 @@ def match_font_name(family: str, available: set[str]) -> str | None:
115
129
  target = family.lower()
116
130
  for name in sorted(available):
117
131
  current = name.lower()
132
+ if "emoji" not in target and " emoji" in current:
133
+ continue
118
134
  if current == target or current.startswith(target + " "):
119
135
  return name
120
136
  return None
@@ -137,6 +153,7 @@ def inspect_recommended_font_groups() -> dict[str, Any]:
137
153
  fontconfig_emoji = _fontconfig_emoji_match()
138
154
  for group_name, group in RECOMMENDED_FONT_GROUPS.items():
139
155
  recommended = list(group["families"])
156
+ preferred = list(group.get("preferred", group["families"][:1]))
140
157
  found = []
141
158
  for family in recommended:
142
159
  match = match_font_name(family, available)
@@ -146,12 +163,15 @@ def inspect_recommended_font_groups() -> dict[str, Any]:
146
163
  for family in fontconfig_emoji.get("families", []):
147
164
  if family not in found:
148
165
  found.append(family)
166
+ missing = [family for family in recommended if not match_font_name(family, available)]
149
167
  result["groups"][group_name] = {
150
168
  "ok": bool(found),
151
169
  "description": group["description"],
170
+ "preferred": preferred,
171
+ "preferred_found": any(family not in missing for family in preferred),
152
172
  "recommended": recommended,
153
173
  "found": found,
154
- "missing": [family for family in recommended if not match_font_name(family, available)],
174
+ "missing": missing,
155
175
  }
156
176
  if group_name == "emoji":
157
177
  result["groups"][group_name]["fontconfig"] = fontconfig_emoji
@@ -43,6 +43,11 @@ from mdtopdf.core.obsidian import (
43
43
 
44
44
  DEFAULT_THEME = "default"
45
45
  SUPPORTED_THEMES = (DEFAULT_THEME,)
46
+ PAGE_MARGIN_FONT_FAMILY = (
47
+ '"Segoe UI", Arial, "Liberation Sans", "DejaVu Sans", '
48
+ '"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", '
49
+ '"Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif'
50
+ )
46
51
 
47
52
 
48
53
  @dataclass(frozen=True)
@@ -990,6 +995,7 @@ def _page_margin_css(page_header: str | None, page_footer: str | None, page_numb
990
995
  " @top-center {",
991
996
  f" content: {_css_string(page_header)};",
992
997
  ' color: #6b7280;',
998
+ f" font-family: {PAGE_MARGIN_FONT_FAMILY};",
993
999
  ' font-size: 8.5pt;',
994
1000
  ' vertical-align: middle;',
995
1001
  " }",
@@ -1003,6 +1009,7 @@ def _page_margin_css(page_header: str | None, page_footer: str | None, page_numb
1003
1009
  " @bottom-center {",
1004
1010
  f" content: {footer_content};",
1005
1011
  ' color: #6b7280;',
1012
+ f" font-family: {PAGE_MARGIN_FONT_FAMILY};",
1006
1013
  ' font-size: 8.5pt;',
1007
1014
  ' vertical-align: middle;',
1008
1015
  " }",
@@ -120,7 +120,7 @@ def _replace_foreign_object_labels(svg: str) -> str:
120
120
  return (
121
121
  f'{match.group(1)}<text x="{width / 2:.3f}" y="{height / 2:.3f}" '
122
122
  'text-anchor="middle" dominant-baseline="central" '
123
- 'font-family="Microsoft YaHei, PingFang SC, Hiragino Sans GB, Noto Sans SC, Noto Sans CJK SC, Arial, sans-serif" '
123
+ 'font-family="Segoe UI, Arial, Liberation Sans, DejaVu Sans, Microsoft YaHei, PingFang SC, Hiragino Sans GB, Noto Sans SC, Noto Sans CJK SC, Source Han Sans SC, sans-serif" '
124
124
  'font-size="16" fill="#333">'
125
125
  f"{escape(text)}"
126
126
  "</text></g>"
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: "mdtopdf"
3
+ description: "Install and run mdtopdf, an agent-friendly Markdown-to-PDF CLI. Use when converting Markdown to PDF or HTML, checking WeasyPrint/mdtopdf runtime health, using Obsidian-style resources, custom CSS, KaTeX, Mermaid, fonts, or JSON diagnostics."
4
+ ---
5
+
6
+ # mdtopdf
7
+
8
+ ## Names
9
+
10
+ - PyPI package: `agent-markdown-pdf`
11
+ - CLI command: `mdtopdf`
12
+ - Python import: `mdtopdf`
13
+
14
+ ## Basic Flow
15
+
16
+ Install or upgrade if the command is missing:
17
+
18
+ ```shell
19
+ python -m pip install -U agent-markdown-pdf
20
+ ```
21
+
22
+ Check the runtime before converting on a new machine:
23
+
24
+ ```shell
25
+ mdtopdf doctor --json
26
+ ```
27
+
28
+ Convert Markdown to PDF:
29
+
30
+ ```shell
31
+ mdtopdf convert INPUT.md -o OUTPUT.pdf --overwrite --json
32
+ ```
33
+
34
+ Use HTML preview only when layout needs debugging:
35
+
36
+ ```shell
37
+ mdtopdf html INPUT.md -o preview.html --overwrite --json
38
+ mdtopdf convert INPUT.md -o OUTPUT.pdf --overwrite --json
39
+ ```
40
+
41
+ ## Useful Options
42
+
43
+ - `--base-url PATH_OR_URL`: resolve relative images and links.
44
+ - `--resource-dir PATH`: resolve Obsidian-style image names such as `![[image.png]]`.
45
+ - `--css print.css`: apply custom print CSS.
46
+ - `--unsafe-html`: allow raw HTML only for trusted local Markdown.
47
+ - `--json`: prefer this for agent workflows.
48
+
49
+ ## Environment
50
+
51
+ `mdtopdf` uses WeasyPrint. If PDF export fails, run:
52
+
53
+ ```shell
54
+ mdtopdf doctor --json
55
+ ```
56
+
57
+ Windows usually needs MSYS2 Pango/GLib/Cairo DLLs:
58
+
59
+ ```powershell
60
+ pacman -S mingw-w64-x86_64-pango
61
+ setx WEASYPRINT_DLL_DIRECTORIES "D:\Environment\msys64\mingw64\bin"
62
+ ```
63
+
64
+ Linux containers need native libraries and fonts:
65
+
66
+ ```shell
67
+ apt-get update
68
+ apt-get install -y --no-install-recommends \
69
+ fontconfig \
70
+ libcairo2 \
71
+ libffi-dev \
72
+ libgdk-pixbuf-2.0-0 \
73
+ libpango-1.0-0 \
74
+ libpangoft2-1.0-0 \
75
+ shared-mime-info \
76
+ fonts-liberation \
77
+ fonts-dejavu-core \
78
+ fonts-noto-cjk
79
+ fc-cache -f
80
+ ```
81
+
82
+ Install optional support only when needed:
83
+
84
+ ```shell
85
+ npm install -g @mermaid-js/mermaid-cli
86
+ apt-get install -y --no-install-recommends fonts-stix fonts-noto-color-emoji
87
+ ```
88
+
89
+ Use Cascadia Code for closer default code-block styling when available:
90
+
91
+ ```shell
92
+ apt-get install -y --no-install-recommends fonts-cascadia-code
93
+ ```
94
+
95
+ ## Failure Handling
96
+
97
+ - Read JSON errors first; do not guess from stderr alone.
98
+ - If conversion fails with WeasyPrint, Pango, GLib, Cairo, or DLL errors, fix the items reported by `doctor --json`.
99
+ - If images are missing, add `--base-url` or `--resource-dir`.
100
+ - If Mermaid diagrams do not render, install local `mmdc`; `mdtopdf` does not call Mermaid.ink or auto-download Mermaid CLI.
101
+ - If CJK text renders as boxes, install a CJK font such as Noto CJK or provide the intended system font.
102
+ - If digits disappear in Chrome/PDFium output, verify the runtime has Latin fonts such as Liberation Sans or DejaVu Sans and render a PDFium screenshot to confirm.
103
+ - Do not look for Pandoc; this CLI uses `markdown-it-py` and WeasyPrint.
@@ -5,7 +5,7 @@
5
5
 
6
6
  :root {
7
7
  color: #172033;
8
- font-family: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", "Segoe UI", "Segoe UI Emoji", Arial, "Apple Color Emoji", "Noto Emoji", "Noto Color Emoji", sans-serif;
8
+ font-family: "Segoe UI", Arial, "Liberation Sans", "DejaVu Sans", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN", sans-serif;
9
9
  font-size: 11.5pt;
10
10
  line-height: 1.55;
11
11
  }
@@ -497,7 +497,7 @@ table.math-array .math-inline {
497
497
  .mathlabel {
498
498
  color: #1474b4;
499
499
  float: right;
500
- font-family: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", "Segoe UI", Arial, sans-serif;
500
+ font-family: "Segoe UI", Arial, "Liberation Sans", "DejaVu Sans", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN", sans-serif;
501
501
  font-size: 0.85em;
502
502
  }
503
503
 
@@ -586,7 +586,7 @@ blockquote.callout .callout-title::before {
586
586
  color: #ffffff;
587
587
  content: "i";
588
588
  display: inline-block;
589
- font-family: "Microsoft YaHei", "PingFang SC", "Noto Sans SC", "Noto Sans CJK SC", "Segoe UI", Arial, sans-serif;
589
+ font-family: "Segoe UI", Arial, "Liberation Sans", "DejaVu Sans", "Microsoft YaHei", "PingFang SC", "Noto Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
590
590
  font-size: 0.78em;
591
591
  font-weight: 800;
592
592
  height: 1.34em;
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agent-markdown-pdf"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Agent-friendly Markdown-to-PDF CLI with HTML preview and JSON diagnostics"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -635,6 +635,7 @@ def test_prepare_mermaid_svg_rewrites_foreign_object_labels():
635
635
 
636
636
  assert "<foreignObject" not in prepared
637
637
  assert "<text" in prepared
638
+ assert 'font-family="Segoe UI, Arial, Liberation Sans, DejaVu Sans' in prepared
638
639
  assert "Node A" in prepared
639
640
 
640
641
 
@@ -780,7 +781,8 @@ def test_theme_loading():
780
781
 
781
782
  assert "@page" in css
782
783
  assert "A4" in css
783
- assert '"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB"' in css
784
+ assert '"Segoe UI", Arial, "Liberation Sans", "DejaVu Sans"' in css
785
+ assert css.index('"Segoe UI", Arial') < css.index('"Microsoft YaHei"')
784
786
  assert ".mdtopdf-emoji {" in css
785
787
  emoji_block = css.rsplit(".mdtopdf-emoji {", 1)[1].split("}", 1)[0]
786
788
  assert emoji_block.index('"Segoe UI Emoji"') < emoji_block.index('"Noto Color Emoji"')
@@ -971,6 +973,7 @@ def test_page_header_footer_can_be_disabled_or_overridden():
971
973
  assert "@bottom-center" not in disabled.css
972
974
  assert 'content: "Quoted \\"Title\\"";' in custom.css
973
975
  assert 'content: "Draft";' in custom.css
976
+ assert 'font-family: "Segoe UI", Arial, "Liberation Sans", "DejaVu Sans"' in custom.css
974
977
  assert "counter(page)" not in custom.css
975
978
 
976
979
 
@@ -1171,6 +1174,7 @@ def test_doctor_json_shape():
1171
1174
  assert "tools" in result
1172
1175
  assert "mermaid" in result["tools"]
1173
1176
  assert "fonts" in result
1177
+ assert "latin_sans" in result["fonts"]["groups"]
1174
1178
  assert "cjk_sans" in result["fonts"]["groups"]
1175
1179
  assert "recommendations" in result
1176
1180
 
@@ -1179,7 +1183,7 @@ def test_doctor_font_groups_match_default_theme_font_fallbacks(monkeypatch):
1179
1183
  monkeypatch.setattr(
1180
1184
  fonts_core,
1181
1185
  "available_font_names",
1182
- lambda: {"Microsoft YaHei", "Consolas", "Cambria Math", "Segoe UI Emoji"},
1186
+ lambda: {"Arial", "Microsoft YaHei", "Consolas", "Cambria Math", "Segoe UI Emoji"},
1183
1187
  )
1184
1188
  monkeypatch.setattr(
1185
1189
  fonts_core,
@@ -1190,12 +1194,121 @@ def test_doctor_font_groups_match_default_theme_font_fallbacks(monkeypatch):
1190
1194
  result = doctor._inspect_fonts()
1191
1195
 
1192
1196
  assert result["ok"] is True
1197
+ assert result["groups"]["latin_sans"]["found"] == ["Arial"]
1198
+ assert result["groups"]["latin_sans"]["preferred_found"] is True
1193
1199
  assert result["groups"]["cjk_sans"]["found"] == ["Microsoft YaHei"]
1200
+ assert result["groups"]["cjk_sans"]["preferred"] == ["Microsoft YaHei"]
1201
+ assert result["groups"]["cjk_sans"]["preferred_found"] is True
1194
1202
  assert result["groups"]["monospace"]["found"] == ["Consolas"]
1203
+ assert result["groups"]["monospace"]["preferred"] == ["Cascadia Mono", "Cascadia Code"]
1204
+ assert result["groups"]["monospace"]["preferred_found"] is False
1195
1205
  assert result["groups"]["math"]["found"] == ["Cambria Math"]
1196
1206
  assert result["groups"]["emoji"]["found"] == ["Segoe UI Emoji"]
1197
1207
 
1198
1208
 
1209
+ def test_doctor_linux_recommends_windows_like_preferred_fonts():
1210
+ result = {
1211
+ "ok": True,
1212
+ "platform": {"system": "Linux"},
1213
+ "packages": {
1214
+ "weasyprint": {"ok": True},
1215
+ "mini-racer": {"ok": True},
1216
+ "latex2mathml": {"ok": True},
1217
+ "matplotlib": {"ok": True},
1218
+ },
1219
+ "tools": {
1220
+ "mermaid": {"ok": True},
1221
+ "fontconfig": {"ok": True},
1222
+ },
1223
+ "fonts": {
1224
+ "groups": {
1225
+ "cjk_sans": {
1226
+ "ok": True,
1227
+ "found": ["Noto Sans CJK SC"],
1228
+ "missing": ["Microsoft YaHei"],
1229
+ },
1230
+ "latin_sans": {
1231
+ "ok": True,
1232
+ "found": ["Liberation Sans"],
1233
+ "missing": ["Segoe UI", "Arial", "DejaVu Sans"],
1234
+ },
1235
+ "monospace": {
1236
+ "ok": True,
1237
+ "found": ["Liberation Mono"],
1238
+ "missing": ["Cascadia Mono", "Cascadia Code"],
1239
+ },
1240
+ "math": {"ok": True, "found": ["STIXGeneral"], "missing": ["Cambria Math"]},
1241
+ "emoji": {"ok": True, "found": ["Noto Color Emoji"], "missing": ["Segoe UI Emoji"]},
1242
+ }
1243
+ },
1244
+ }
1245
+
1246
+ recommendations = doctor._recommendations(result)
1247
+
1248
+ assert any("Microsoft YaHei" in item and "Windows-like" in item for item in recommendations)
1249
+ assert any("Cascadia Code" in item and "code blocks" in item for item in recommendations)
1250
+
1251
+
1252
+ def test_doctor_linux_recommends_fontconfig_when_missing():
1253
+ result = {
1254
+ "ok": True,
1255
+ "platform": {"system": "Linux"},
1256
+ "packages": {
1257
+ "weasyprint": {"ok": True},
1258
+ "mini-racer": {"ok": True},
1259
+ "latex2mathml": {"ok": True},
1260
+ "matplotlib": {"ok": True},
1261
+ },
1262
+ "tools": {
1263
+ "mermaid": {"ok": True},
1264
+ "fontconfig": {"ok": False, "error": "fc-match was not found on PATH."},
1265
+ },
1266
+ "fonts": {
1267
+ "groups": {
1268
+ "cjk_sans": {"ok": True, "found": ["Microsoft YaHei"], "missing": []},
1269
+ "latin_sans": {"ok": True, "found": ["Arial"], "missing": []},
1270
+ "monospace": {"ok": True, "found": ["Cascadia Code"], "missing": []},
1271
+ "math": {"ok": True, "found": ["Cambria Math"], "missing": []},
1272
+ "emoji": {"ok": True, "found": ["Segoe UI Emoji"], "missing": []},
1273
+ }
1274
+ },
1275
+ }
1276
+
1277
+ recommendations = doctor._recommendations(result)
1278
+
1279
+ assert any("fontconfig" in item for item in recommendations)
1280
+
1281
+
1282
+ def test_doctor_recommends_latin_fonts_when_missing():
1283
+ result = {
1284
+ "ok": True,
1285
+ "platform": {"system": "Linux"},
1286
+ "packages": {
1287
+ "weasyprint": {"ok": True},
1288
+ "mini-racer": {"ok": True},
1289
+ "latex2mathml": {"ok": True},
1290
+ "matplotlib": {"ok": True},
1291
+ },
1292
+ "tools": {
1293
+ "mermaid": {"ok": True},
1294
+ "fontconfig": {"ok": True},
1295
+ },
1296
+ "fonts": {
1297
+ "groups": {
1298
+ "latin_sans": {"ok": False, "found": [], "missing": ["Segoe UI", "Arial", "Liberation Sans"]},
1299
+ "cjk_sans": {"ok": True, "found": ["Noto Sans CJK SC"], "missing": ["Microsoft YaHei"]},
1300
+ "monospace": {"ok": True, "found": ["Liberation Mono"], "missing": ["Cascadia Code"]},
1301
+ "math": {"ok": True, "found": ["STIXGeneral"], "missing": ["Cambria Math"]},
1302
+ "emoji": {"ok": True, "found": ["Noto Color Emoji"], "missing": ["Segoe UI Emoji"]},
1303
+ }
1304
+ },
1305
+ }
1306
+
1307
+ recommendations = doctor._recommendations(result)
1308
+
1309
+ assert any("Latin sans" in item and "digits" in item for item in recommendations)
1310
+
1311
+
1199
1312
  def test_doctor_reports_missing_mini_racer(monkeypatch):
1200
1313
  real_import = importlib.import_module
1201
1314
 
@@ -1,108 +0,0 @@
1
- ---
2
- name: "mdtopdf"
3
- description: "Use when an agent needs to install or run mdtopdf: an agent-friendly Markdown-to-PDF CLI with JSON diagnostics, HTML preview, Obsidian-compatible Markdown, local KaTeX math, optional local Mermaid rendering, and WeasyPrint environment checks."
4
- ---
5
-
6
- # mdtopdf
7
-
8
- Use this skill to turn local Markdown into a local PDF with the `mdtopdf` CLI.
9
- Prefer the CLI over the Python API unless the user explicitly asks for code
10
- integration.
11
-
12
- ## Names
13
-
14
- | Purpose | Name |
15
- | --- | --- |
16
- | PyPI distribution | `agent-markdown-pdf` |
17
- | CLI command | `mdtopdf` |
18
- | Python import | `mdtopdf` |
19
-
20
- Install the package when the command is missing:
21
-
22
- ```powershell
23
- python -m pip install agent-markdown-pdf
24
- ```
25
-
26
- ## Workflow
27
-
28
- Check a new or unknown machine first:
29
-
30
- ```powershell
31
- mdtopdf doctor --json
32
- ```
33
-
34
- Generate a PDF:
35
-
36
- ```powershell
37
- mdtopdf convert .\input.md -o .\output.pdf --overwrite --json
38
- ```
39
-
40
- Use HTML preview only when layout needs debugging:
41
-
42
- ```powershell
43
- mdtopdf html .\input.md -o .\preview.html --overwrite --json
44
- mdtopdf convert .\input.md -o .\output.pdf --overwrite --json
45
- ```
46
-
47
- ## Resource Paths
48
-
49
- - Use `--base-url PATH_OR_URL` when the Markdown contains relative images or links.
50
- - Use `--resource-dir PATH` for Obsidian-style image names such as `![[image.png]]`.
51
- - Use `--css custom.css` when the user provides print CSS.
52
- - Conversion checks CSS font stacks after theme and custom CSS are combined.
53
- Missing fonts are warnings, not hard failures.
54
- - Use `--unsafe-html` only for trusted local Markdown.
55
-
56
- ## Environment Fixes
57
-
58
- `mdtopdf` uses WeasyPrint, so PDF output needs native Pango, GLib, and Cairo
59
- libraries.
60
-
61
- On Windows, run `mdtopdf doctor --json` before guessing. If the JSON output says
62
- native DLLs are missing, install MSYS2 Pango and set the DLL directory for that
63
- machine, for example:
64
-
65
- ```powershell
66
- pacman -S mingw-w64-x86_64-pango
67
- setx WEASYPRINT_DLL_DIRECTORIES "D:\Environment\msys64\mingw64\bin"
68
- ```
69
-
70
- The exact MSYS2 path may differ.
71
-
72
- On Linux containers, install the native WeasyPrint packages before installing
73
- `agent-markdown-pdf`.
74
-
75
- For stable Chinese/Japanese/Korean and emoji output in containers, install the
76
- CJK and emoji fonts the user wants. Emoji spans prefer Segoe UI Emoji on every
77
- platform, including Linux. Linux containers only get the same glyphs when that
78
- font is available in the runtime; otherwise mdtopdf falls back to installed
79
- emoji fonts such as Apple Color Emoji, Noto Emoji, or Noto Color Emoji. Noto
80
- CJK plus Noto Color Emoji is still a practical open-font fallback on Debian or
81
- Ubuntu, but color emoji in the final PDF is best-effort because it depends on
82
- WeasyPrint, Pango/Cairo, and the PDF viewer:
83
-
84
- ```shell
85
- apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
86
- fc-cache -f
87
- ```
88
-
89
- `mdtopdf doctor --json` reports recommended CJK, emoji, monospace, and math
90
- fallback font availability. Missing fonts do not always stop conversion, but
91
- they can change glyph coverage, emoji size, line breaks, and pagination.
92
-
93
- ## Failure Handling
94
-
95
- - Prefer `--json` so failures are structured.
96
- - If CJK text renders as boxes or pagination differs between machines, install
97
- Noto CJK fonts and rerun the conversion.
98
- - If emoji render as boxes, missing glyphs, or tiny glyphs on Linux, provide
99
- Segoe UI Emoji in the runtime or install a fallback emoji font, run
100
- `fc-cache -f`, and rerun the conversion.
101
- - If conversion fails with a WeasyPrint, Pango, GLib, Cairo, or DLL error, run
102
- `mdtopdf doctor --json` and follow its recommendations.
103
- - If Mermaid diagrams do not render, check whether local `mmdc` is installed.
104
- Mermaid is optional; `mdtopdf` does not call Mermaid.ink or download Mermaid
105
- CLI during conversion.
106
- - Do not look for Pandoc; this CLI uses `markdown-it-py` and WeasyPrint.
107
- - Report the exact command, JSON error, and output path when handing results
108
- back to the user.