agent-markdown-pdf 0.2.0__tar.gz → 0.2.2__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.2}/PKG-INFO +35 -24
  2. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/README.md +35 -24
  3. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/PKG-INFO +35 -24
  4. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/doctor.py +96 -11
  5. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/fonts.py +41 -2
  6. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/markdown.py +7 -0
  7. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/mermaid.py +1 -1
  8. agent_markdown_pdf-0.2.2/mdtopdf/skills/SKILL.md +107 -0
  9. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/themes/default.css +3 -3
  10. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/pyproject.toml +1 -1
  11. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/tests/test_core.py +181 -3
  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.2}/LICENSE +0 -0
  14. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/SOURCES.txt +0 -0
  15. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/dependency_links.txt +0 -0
  16. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/entry_points.txt +0 -0
  17. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/requires.txt +0 -0
  18. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/agent_markdown_pdf.egg-info/top_level.txt +0 -0
  19. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/__init__.py +0 -0
  20. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/__main__.py +0 -0
  21. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/api.py +0 -0
  22. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/__init__.py +0 -0
  23. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/html.py +0 -0
  24. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/inline.py +0 -0
  25. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/katex.py +0 -0
  26. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/obsidian.py +0 -0
  27. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/core/pdf.py +0 -0
  28. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/mdtopdf_cli.py +0 -0
  29. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/LICENSE +0 -0
  30. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/contrib/mhchem.min.js +0 -0
  31. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  32. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  33. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  34. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  35. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  36. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  37. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  38. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  39. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  40. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  41. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  42. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  43. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  44. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  45. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  46. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  47. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  48. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  49. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  50. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  51. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  52. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  53. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  54. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  55. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  56. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  57. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  58. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  59. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  60. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  61. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  62. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  63. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  64. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  65. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  66. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  67. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  68. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  69. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  70. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  71. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  72. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  73. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  74. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  75. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  76. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  77. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  78. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  79. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  80. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  81. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  82. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  83. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  84. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  85. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  86. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  87. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  88. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  89. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  90. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  91. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/katex.min.css +0 -0
  92. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/mdtopdf/vendor/katex/dist/katex.min.js +0 -0
  93. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/setup.cfg +0 -0
  94. {agent_markdown_pdf-0.2.0 → agent_markdown_pdf-0.2.2}/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.2
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,31 +323,40 @@ 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.
331
330
 
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:
335
-
336
- Emoji are rendered through the system emoji font. The default theme prefers
337
- `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
338
- usually provides it; Linux containers only get the same glyphs if the runtime
339
- provides that font. If Segoe UI Emoji is not available, the theme falls back to
340
- `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
341
- fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
342
- Pango/Cairo, and the PDF viewer.
343
-
344
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
331
+ For Linux containers or agent sandboxes, use open fonts that can be installed
332
+ from the distribution package manager. The recommended baseline is:
345
333
 
346
334
  ```shell
347
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
335
+ sudo apt-get install -y --no-install-recommends \
336
+ fontconfig \
337
+ fonts-liberation \
338
+ fonts-dejavu-core \
339
+ fonts-noto-cjk \
340
+ fonts-stix
348
341
  fc-cache -f
349
342
  ```
350
343
 
344
+ With that setup, Linux output uses `Liberation Sans` / `DejaVu Sans` for Latin
345
+ text and digits, `Noto Sans CJK SC` for Chinese, and STIX for math fallback.
346
+ Microsoft YaHei and Segoe UI Emoji are not Linux runtime requirements and are
347
+ not installed or distributed by `mdtopdf`.
348
+
349
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
350
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
351
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
352
+ Cascadia Code yourself or let the theme fall back to the installed monospace
353
+ fonts.
354
+
355
+ Emoji are rendered through the system emoji font. On Linux, prefer monochrome
356
+ `Noto Emoji` for stable PDF layout. `Noto Color Emoji` is easier to install from
357
+ many distro package managers and is safe to use as a fallback, but color emoji
358
+ often render too small or misaligned in WeasyPrint/Pango/Cairo/PDFium output.
359
+
351
360
  On Windows, install the native libraries separately. A common MSYS2 setup is:
352
361
 
353
362
  ```powershell
@@ -368,7 +377,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
368
377
  ```
369
378
 
370
379
  Run this after installation. The JSON output also reports whether recommended
371
- CJK, emoji, monospace, and math fallback fonts are present:
380
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
372
381
 
373
382
  ```shell
374
383
  mdtopdf doctor --json
@@ -396,6 +405,8 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
396
405
  `mdtopdf/vendor/katex/LICENSE`.
397
406
 
398
407
  `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.
408
+ fonts. The default theme references local system fonts such as Segoe UI,
409
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Sans CJK SC,
410
+ Noto Emoji, Noto Color Emoji, Cascadia Code, and Consolas, but those font files come from
411
+ the user's operating system or runtime environment. Public Linux images should
412
+ prefer the open-font baseline above.
@@ -282,31 +282,40 @@ 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.
290
-
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:
294
-
295
- Emoji are rendered through the system emoji font. The default theme prefers
296
- `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
297
- usually provides it; Linux containers only get the same glyphs if the runtime
298
- provides that font. If Segoe UI Emoji is not available, the theme falls back to
299
- `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
300
- fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
301
- Pango/Cairo, and the PDF viewer.
302
-
303
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
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.
289
+
290
+ For Linux containers or agent sandboxes, use open fonts that can be installed
291
+ from the distribution package manager. The recommended baseline is:
304
292
 
305
293
  ```shell
306
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
294
+ sudo apt-get install -y --no-install-recommends \
295
+ fontconfig \
296
+ fonts-liberation \
297
+ fonts-dejavu-core \
298
+ fonts-noto-cjk \
299
+ fonts-stix
307
300
  fc-cache -f
308
301
  ```
309
302
 
303
+ With that setup, Linux output uses `Liberation Sans` / `DejaVu Sans` for Latin
304
+ text and digits, `Noto Sans CJK SC` for Chinese, and STIX for math fallback.
305
+ Microsoft YaHei and Segoe UI Emoji are not Linux runtime requirements and are
306
+ not installed or distributed by `mdtopdf`.
307
+
308
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
309
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
310
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
311
+ Cascadia Code yourself or let the theme fall back to the installed monospace
312
+ fonts.
313
+
314
+ Emoji are rendered through the system emoji font. On Linux, prefer monochrome
315
+ `Noto Emoji` for stable PDF layout. `Noto Color Emoji` is easier to install from
316
+ many distro package managers and is safe to use as a fallback, but color emoji
317
+ often render too small or misaligned in WeasyPrint/Pango/Cairo/PDFium output.
318
+
310
319
  On Windows, install the native libraries separately. A common MSYS2 setup is:
311
320
 
312
321
  ```powershell
@@ -327,7 +336,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
327
336
  ```
328
337
 
329
338
  Run this after installation. The JSON output also reports whether recommended
330
- CJK, emoji, monospace, and math fallback fonts are present:
339
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
331
340
 
332
341
  ```shell
333
342
  mdtopdf doctor --json
@@ -355,6 +364,8 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
355
364
  `mdtopdf/vendor/katex/LICENSE`.
356
365
 
357
366
  `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.
367
+ fonts. The default theme references local system fonts such as Segoe UI,
368
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Sans CJK SC,
369
+ Noto Emoji, Noto Color Emoji, Cascadia Code, and Consolas, but those font files come from
370
+ the user's operating system or runtime environment. Public Linux images should
371
+ prefer the open-font baseline above.
@@ -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.2
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,31 +323,40 @@ 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.
331
330
 
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:
335
-
336
- Emoji are rendered through the system emoji font. The default theme prefers
337
- `Segoe UI Emoji` for emoji spans on every platform, including Linux. Windows
338
- usually provides it; Linux containers only get the same glyphs if the runtime
339
- provides that font. If Segoe UI Emoji is not available, the theme falls back to
340
- `Apple Color Emoji`, `Noto Emoji`, `Noto Color Emoji`, and other installed emoji
341
- fonts. Whether the final PDF keeps color emoji still depends on WeasyPrint,
342
- Pango/Cairo, and the PDF viewer.
343
-
344
- On Debian or Ubuntu, this is a practical open-font fallback baseline:
331
+ For Linux containers or agent sandboxes, use open fonts that can be installed
332
+ from the distribution package manager. The recommended baseline is:
345
333
 
346
334
  ```shell
347
- sudo apt-get install -y fonts-noto-cjk fonts-noto-color-emoji fonts-stix fonts-dejavu-core
335
+ sudo apt-get install -y --no-install-recommends \
336
+ fontconfig \
337
+ fonts-liberation \
338
+ fonts-dejavu-core \
339
+ fonts-noto-cjk \
340
+ fonts-stix
348
341
  fc-cache -f
349
342
  ```
350
343
 
344
+ With that setup, Linux output uses `Liberation Sans` / `DejaVu Sans` for Latin
345
+ text and digits, `Noto Sans CJK SC` for Chinese, and STIX for math fallback.
346
+ Microsoft YaHei and Segoe UI Emoji are not Linux runtime requirements and are
347
+ not installed or distributed by `mdtopdf`.
348
+
349
+ Code blocks prefer `Cascadia Mono` / `Cascadia Code`, then `Consolas`,
350
+ `Noto Sans Mono CJK SC`, `Liberation Mono`, and `DejaVu Sans Mono`. On Debian,
351
+ `fonts-cascadia-code` provides Cascadia fonts; on other Linux images, provide
352
+ Cascadia Code yourself or let the theme fall back to the installed monospace
353
+ fonts.
354
+
355
+ Emoji are rendered through the system emoji font. On Linux, prefer monochrome
356
+ `Noto Emoji` for stable PDF layout. `Noto Color Emoji` is easier to install from
357
+ many distro package managers and is safe to use as a fallback, but color emoji
358
+ often render too small or misaligned in WeasyPrint/Pango/Cairo/PDFium output.
359
+
351
360
  On Windows, install the native libraries separately. A common MSYS2 setup is:
352
361
 
353
362
  ```powershell
@@ -368,7 +377,7 @@ setx WEASYPRINT_DLL_DIRECTORIES "C:\msys64\mingw64\bin"
368
377
  ```
369
378
 
370
379
  Run this after installation. The JSON output also reports whether recommended
371
- CJK, emoji, monospace, and math fallback fonts are present:
380
+ Latin, CJK, emoji, monospace, and math fallback fonts are present:
372
381
 
373
382
  ```shell
374
383
  mdtopdf doctor --json
@@ -396,6 +405,8 @@ MIT. Bundled KaTeX assets are also distributed under the MIT license; see
396
405
  `mdtopdf/vendor/katex/LICENSE`.
397
406
 
398
407
  `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.
408
+ fonts. The default theme references local system fonts such as Segoe UI,
409
+ Microsoft YaHei, PingFang SC, Segoe UI Emoji, Noto Sans CJK SC,
410
+ Noto Emoji, Noto Color Emoji, Cascadia Code, and Consolas, but those font files come from
411
+ the user's operating system or runtime environment. Public Linux images should
412
+ prefer the open-font baseline above.
@@ -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
@@ -50,10 +52,11 @@ def run_doctor() -> dict[str, Any]:
50
52
 
51
53
  add_weasyprint_dll_directories()
52
54
 
55
+ platform_system = platform.system()
53
56
  result: dict[str, Any] = {
54
57
  "ok": False,
55
58
  "platform": {
56
- "system": platform.system(),
59
+ "system": platform_system,
57
60
  "release": platform.release(),
58
61
  "machine": platform.machine(),
59
62
  },
@@ -67,7 +70,7 @@ def run_doctor() -> dict[str, Any]:
67
70
  "packages": {},
68
71
  "tools": {},
69
72
  "native_libraries": _inspect_native_libraries(),
70
- "fonts": _inspect_fonts(),
73
+ "fonts": _inspect_fonts(platform_system),
71
74
  "recommendations": [],
72
75
  }
73
76
 
@@ -76,6 +79,8 @@ def run_doctor() -> dict[str, Any]:
76
79
  result["packages"]["latex2mathml"] = _check_python_package("latex2mathml")
77
80
  result["packages"]["matplotlib"] = _check_python_package("matplotlib")
78
81
  result["tools"]["mermaid"] = inspect_mermaid_backend()
82
+ if result["platform"]["system"] == "Linux":
83
+ result["tools"]["fontconfig"] = _inspect_fontconfig()
79
84
  result["ok"] = all(info["ok"] for info in result["packages"].values())
80
85
  result["recommendations"] = _recommendations(result)
81
86
  return result
@@ -207,12 +212,42 @@ def _env_dll_directories() -> list[str]:
207
212
  return [part.strip() for part in raw.split(os.pathsep) if part.strip()]
208
213
 
209
214
 
210
- def _inspect_fonts() -> dict[str, Any]:
211
- return inspect_recommended_font_groups()
215
+ def _inspect_fonts(platform_system: str | None = None) -> dict[str, Any]:
216
+ return inspect_recommended_font_groups(platform_system)
217
+
218
+
219
+ def _inspect_fontconfig() -> dict[str, Any]:
220
+ executable = shutil.which("fc-match")
221
+ result: dict[str, Any] = {
222
+ "ok": False,
223
+ "executable": executable,
224
+ "sample": None,
225
+ "error": None,
226
+ }
227
+ if not executable:
228
+ result["error"] = "fc-match was not found on PATH."
229
+ return result
230
+
231
+ try:
232
+ proc = subprocess.run(
233
+ [executable, "-f", "%{family}\n", "sans-serif"],
234
+ check=True,
235
+ capture_output=True,
236
+ text=True,
237
+ timeout=5,
238
+ )
239
+ except Exception as exc:
240
+ result["error"] = f"{type(exc).__name__}: {exc}"
241
+ return result
242
+
243
+ result["sample"] = proc.stdout.strip() or None
244
+ result["ok"] = True
245
+ return result
212
246
 
213
247
 
214
248
  def _recommendations(result: dict[str, Any]) -> list[str]:
215
249
  recommendations: list[str] = []
250
+ is_linux = result.get("platform", {}).get("system") == "Linux"
216
251
  package_info = result.get("packages", {}).get("weasyprint", {})
217
252
  if not package_info.get("ok"):
218
253
  recommendations.append("Install Python dependencies with: python -m pip install agent-markdown-pdf")
@@ -232,30 +267,80 @@ def _recommendations(result: dict[str, Any]) -> list[str]:
232
267
  "Optional: install Mermaid rendering support with Node.js plus: "
233
268
  "npm install -g @mermaid-js/mermaid-cli"
234
269
  )
270
+ fontconfig_info = result.get("tools", {}).get("fontconfig")
271
+ if is_linux and fontconfig_info and not fontconfig_info.get("ok"):
272
+ recommendations.append(
273
+ "Install fontconfig so WeasyPrint/Pango can resolve system fonts, for example: "
274
+ "sudo apt-get install fontconfig"
275
+ )
235
276
 
236
277
  font_info = result.get("fonts", {})
237
278
  font_groups = font_info.get("groups", {})
238
279
  if font_info.get("error"):
239
280
  recommendations.append("Font inspection failed; run conversion once and verify CJK text visually.")
240
- if font_groups.get("cjk_sans") and not font_groups["cjk_sans"].get("ok"):
281
+ if font_groups.get("latin_sans") and not font_groups["latin_sans"].get("ok"):
241
282
  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"
283
+ "Install a Latin sans font so digits, dates, versions, and page counters avoid CJK font subsets. "
284
+ "On Debian or Ubuntu, use: sudo apt-get install fonts-liberation fonts-dejavu-core"
244
285
  )
286
+ if font_groups.get("cjk_sans") and not font_groups["cjk_sans"].get("ok"):
287
+ if is_linux:
288
+ recommendations.append(
289
+ "Install Noto CJK for Chinese text on Linux: sudo apt-get install fonts-noto-cjk"
290
+ )
291
+ else:
292
+ recommendations.append(
293
+ "Install or enable a CJK sans font for Chinese text, such as Microsoft YaHei, "
294
+ "PingFang SC, Noto Sans CJK SC, or Source Han Sans SC."
295
+ )
245
296
  if font_groups.get("monospace") and not font_groups["monospace"].get("ok"):
246
297
  recommendations.append(
247
- "Optional: install a monospace font such as Cascadia Code or Liberation Mono for stable code blocks."
298
+ "Install a monospace font for code blocks. On Debian or Ubuntu, use: "
299
+ "sudo apt-get install fonts-cascadia-code if that package is available; "
300
+ "otherwise provide Cascadia Code in the runtime."
301
+ )
302
+ elif (
303
+ is_linux
304
+ and font_groups.get("monospace")
305
+ and "Cascadia Mono" in font_groups["monospace"].get("missing", [])
306
+ and "Cascadia Code" in font_groups["monospace"].get("missing", [])
307
+ ):
308
+ recommendations.append(
309
+ "Optional: install Cascadia Code on Linux for default-theme code blocks: "
310
+ "sudo apt-get install fonts-cascadia-code if that package is available, "
311
+ "or provide Cascadia Code in the runtime."
248
312
  )
249
313
  if font_groups.get("math") and not font_groups["math"].get("ok"):
250
314
  recommendations.append(
251
315
  "Optional: install STIX fonts for math fallback, for example: sudo apt-get install fonts-stix"
252
316
  )
253
317
  if font_groups.get("emoji") and not font_groups["emoji"].get("ok"):
318
+ if is_linux:
319
+ recommendations.append(
320
+ "Provide a monochrome emoji font such as Noto Emoji for stable PDF output on Linux. "
321
+ "Noto Color Emoji is widely packaged, but PDF viewers can render color emoji too small "
322
+ "or misaligned."
323
+ )
324
+ else:
325
+ recommendations.append(
326
+ "Install or enable a system emoji font such as Segoe UI Emoji, Apple Color Emoji, "
327
+ "Noto Color Emoji, or Twemoji Mozilla."
328
+ )
329
+ elif (
330
+ is_linux
331
+ and font_groups.get("emoji")
332
+ and "Noto Emoji" in font_groups["emoji"].get("missing", [])
333
+ and "Noto Color Emoji" in font_groups["emoji"].get("found", [])
334
+ ):
254
335
  recommendations.append(
255
- "Provide Segoe UI Emoji in the runtime if you want the default theme's first-choice "
256
- "emoji glyphs. If that is not available, install another emoji font and run fc-cache -f."
336
+ "Noto Color Emoji was found. It provides glyph coverage, but color emoji can render too small "
337
+ "or misaligned in WeasyPrint/PDFium output. Prefer monochrome Noto Emoji if emoji layout matters."
257
338
  )
258
- elif font_groups.get("emoji") and "Segoe UI Emoji" in font_groups["emoji"].get("missing", []):
339
+ elif (
340
+ not is_linux
341
+ and font_groups.get("emoji")
342
+ and "Segoe UI Emoji" in font_groups["emoji"].get("missing", [])
343
+ ):
259
344
  recommendations.append(
260
345
  "Optional: provide Segoe UI Emoji if you want the default theme's preferred emoji glyphs. "
261
346
  "Existing emoji fallback fonts will still be used."
@@ -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",
@@ -77,6 +91,14 @@ RECOMMENDED_FONT_GROUPS = {
77
91
  ),
78
92
  },
79
93
  }
94
+ PLATFORM_PREFERRED_FONT_GROUPS = {
95
+ "Linux": {
96
+ "latin_sans": ("Liberation Sans", "DejaVu Sans"),
97
+ "cjk_sans": ("Noto Sans CJK SC", "Noto Sans SC"),
98
+ "math": ("STIXGeneral", "STIX Two Math"),
99
+ "emoji": ("Noto Emoji",),
100
+ },
101
+ }
80
102
  CJK_CAPABLE_FONT_FAMILIES = (
81
103
  "Noto Sans SC",
82
104
  "Noto Sans CJK SC",
@@ -115,12 +137,14 @@ def match_font_name(family: str, available: set[str]) -> str | None:
115
137
  target = family.lower()
116
138
  for name in sorted(available):
117
139
  current = name.lower()
140
+ if "emoji" not in target and " emoji" in current:
141
+ continue
118
142
  if current == target or current.startswith(target + " "):
119
143
  return name
120
144
  return None
121
145
 
122
146
 
123
- def inspect_recommended_font_groups() -> dict[str, Any]:
147
+ def inspect_recommended_font_groups(platform_system: str | None = None) -> dict[str, Any]:
124
148
  result: dict[str, Any] = {
125
149
  "ok": False,
126
150
  "backend": "matplotlib.font_manager",
@@ -137,6 +161,7 @@ def inspect_recommended_font_groups() -> dict[str, Any]:
137
161
  fontconfig_emoji = _fontconfig_emoji_match()
138
162
  for group_name, group in RECOMMENDED_FONT_GROUPS.items():
139
163
  recommended = list(group["families"])
164
+ preferred = list(_preferred_families(group_name, group, platform_system))
140
165
  found = []
141
166
  for family in recommended:
142
167
  match = match_font_name(family, available)
@@ -146,12 +171,15 @@ def inspect_recommended_font_groups() -> dict[str, Any]:
146
171
  for family in fontconfig_emoji.get("families", []):
147
172
  if family not in found:
148
173
  found.append(family)
174
+ missing = [family for family in recommended if not match_font_name(family, available)]
149
175
  result["groups"][group_name] = {
150
176
  "ok": bool(found),
151
177
  "description": group["description"],
178
+ "preferred": preferred,
179
+ "preferred_found": any(family not in missing for family in preferred),
152
180
  "recommended": recommended,
153
181
  "found": found,
154
- "missing": [family for family in recommended if not match_font_name(family, available)],
182
+ "missing": missing,
155
183
  }
156
184
  if group_name == "emoji":
157
185
  result["groups"][group_name]["fontconfig"] = fontconfig_emoji
@@ -160,6 +188,17 @@ def inspect_recommended_font_groups() -> dict[str, Any]:
160
188
  return result
161
189
 
162
190
 
191
+ def _preferred_families(
192
+ group_name: str,
193
+ group: dict[str, Any],
194
+ platform_system: str | None,
195
+ ) -> tuple[str, ...]:
196
+ platform_preferred = PLATFORM_PREFERRED_FONT_GROUPS.get(platform_system or "", {})
197
+ if isinstance(platform_preferred, dict) and group_name in platform_preferred:
198
+ return platform_preferred[group_name]
199
+ return group.get("preferred", group["families"][:1])
200
+
201
+
163
202
  def inspect_css_font_usage(css: str, *, document_text: str | None = None) -> dict[str, Any]:
164
203
  result: dict[str, Any] = {
165
204
  "ok": True,
@@ -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>"