degun-osint1k downloadsExport notes as styled PDF with configurable themes, logos, headers/footers, and legal notices.
Export Markdown notes to beautifully styled PDFs with configurable themes: colors, logo, header/footer, watermark, PDF bookmarks, legal notice.
Configuration is now layered: the theme carries the defaults, the note overrides them, the export modal has the last word.
theme: frontmatter key: pin a base theme per noteorder: frontmatter key: sort chapters in a merged export, without 01- filename prefixes⚠️ Breaking: rhino-pdf frontmatter must now be valid YAML — quote values containing {, : or #. See the changelog.
.obsidian/rhino-pdf-themes.json, outside the plugin folder (survives plugin updates)rhino-pdf key, including which theme to use{title}, {filename}, {author}, {date}, {time} and {fm.key} (any frontmatter field), resolved at export time<!-- pagebreak --> in a note to force a new pagecoverInfo) or per themeorder frontmatter key{page} / {pages}, via paged.js CSS counters)Settings → Community plugins → Browse → search "Rhino PDF Export" → Install → Enable. Or get it there : https://community.obsidian.md/plugins/rhino-pdf-export
Download main.js, manifest.json and styles.css from the latest release, then copy them into your vault at .obsidian/plugins/rhino-pdf-export/.
git clone https://github.com/degun-osint/obsidian-rhino-pdf-export.git
cd obsidian-rhino-pdf-export
npm install && npm run build
cp main.js manifest.json styles.css /path/to/vault/.obsidian/plugins/rhino-pdf-export/
Export note as PDF, or Export note as PDF with last settings to skip the modal.md file → Export note as PDFExport folder as PDFThe export modal shows a live PDF preview, lets you pick the theme, and opens a "This document" section for the settings you want to change just this once.
For folder export, a toggle lets you merge all notes into a single PDF with a global table of contents.
Three layers, resolved in this order — the export modal wins, then the note, then the theme:
| Layer | Holds | Edited in |
|---|---|---|
| Theme | The charter: colors, fonts, logo, margins, page size, legal notice | Settings → theme editor |
| Note | What is specific to this document: subtitle, watermark, classification, cover info | The rhino-pdf frontmatter key |
| Export | A one-off change, before hitting Export | The "This document" section |
Two buttons bridge the layers. Save to note writes the modal's overrides into the note's frontmatter — that is how a one-off tweak becomes reproducible. Save as theme default promotes them to the theme instead, duplicating it first if it is built-in.
Add a rhino-pdf block in a note's frontmatter to override theme settings:
---
rhino-pdf:
theme: "Corporate Report" # pin a theme, by name or id
primaryColor: "#e63946"
showCover: false
subtitle: "My subtitle"
watermarkText: "DRAFT"
headerText: "{title} — {date}"
classificationText: "RESTRICTED"
pageBreakBeforeH2: true
coverInfo: [author, case_id] # cover info block for this note
order: 2 # position in a merged folder export
margins:
top: 30mm
bottom: 30mm
---
Every theme field is supported except id, name and builtin — a note must not be able to rename the theme it resolves against.
Values must be valid YAML. Quote anything containing {, : or #, or YAML will read it as structure:
rhino-pdf:
paginationFormat: "{page} / {pages}" # quoted — `{` would open a flow mapping
primaryColor: "#e63946" # quoted — `#` would start a comment
Unknown or invalid keys are ignored rather than applied, and the export modal shows a badge listing them.
Header, footer and classification text resolve these placeholders at export time:
| Variable | Value |
|---|---|
{title} |
Note title (first # H1, or filename) |
{filename} |
Note file name (without extension) |
{author} |
Frontmatter author field |
{date} |
Export date (locale format) |
{time} |
Export time (locale format) |
{fm.KEY} |
Any frontmatter field, e.g. {fm.case_id} |
Put this on its own line anywhere in a note to force a new page:
<!-- pagebreak -->
In the theme editor (Page layout → "Page breaks"), toggle Before heading 1/2/3 to start a new page before every heading of that level. Cover and table-of-contents headings are never affected.
Set pageBreakBeforeH2: true in a note's frontmatter and it applies to that note only, including inside a merged folder export.
In a merged folder export, notes are sorted by their rhino-pdf.order frontmatter key, then alphabetically. Notes without one come last.
---
rhino-pdf:
order: 1
---
Export note as PDF with last settings exports without opening the modal. It uses the theme pinned by the note's rhino-pdf.theme, falling back to the last theme you used, and writes to the folder of your last export (or next to the note). It overwrites an existing PDF of the same name without asking — the destination is shown in the notice.
Set Classification text in the theme editor (or classificationText in frontmatter) to print a centered banner on every page, cover included. It supports the text variables above, so DIFFUSION RESTREINTE — {fm.case_id} works. Color is configurable.
Enable PDF metadata in the theme editor to fill the generated PDF's document properties from the note frontmatter (off by default):
| PDF property | Frontmatter field |
|---|---|
| Title | note title |
| Author | author |
| Subject | subject |
| Keywords | keywords or tags |
In the export modal, under This document → Cover info block, each frontmatter field of the note appears as a checkbox. Tick the ones you want and they are listed as a label/value table on the cover page (requires a theme with a cover). Example frontmatter:
---
author: Degun
subject: OSINT report
case_id: AFFAIRE-2026-0042
tags: [osint, report]
---
The selection is remembered where you save it: Save to note writes coverInfo: [author, case_id] into the note, and Save as theme default stores it as the theme's coverInfoFields, applied to every note exported with it.
A font named in Body font / Code font must be installed on the machine running the export, or it falls back silently. To avoid that, drop the font files in your vault and reference them under Settings → theme → Embedded fonts: they get inlined into the PDF, so the document renders identically everywhere.
Drop your font files in the vault, then either:
Either way the family, weight and style are read from the font file itself, not guessed from its name. Variable fonts are detected and get their real range (100 900 for Inter). Correct any field afterwards if you want to.
| Field | Example |
|---|---|
| Family | Marianne |
| File | assets/fonts/Marianne-Regular.woff2 |
| Weight | 400, or 100 900 for a variable font |
| Style | Normal / Italic |
Add one row per weight and style you actually use — with only a regular file, the bold is synthesized by the renderer and it shows in print. Then use the family in the font fields: 'Marianne', sans-serif.
Supported formats are woff2 (recommended), woff, ttf and otf. Font collections (.ttc) are not supported — @font-face cannot use them. An embedded family takes precedence over a system font of the same name. If a file is missing or invalid, the export tells you rather than quietly falling back.
Inter and JetBrains Mono are already bundled with the plugin — no need to add them.
The External links theme option controls how external (http/https) link
addresses are rendered:
(https://…) after the link textThe footer page number uses a template with {page} and {pages}, so you can set
e.g. {page} / {pages}, Page {page} of {pages} or - {page} -.
Enable Number headings in the theme editor to automatically prefix H2/H3 with
1, 1.1, … The numbering is computed at print time and stays in sync with the
table of contents.
Table-of-contents entries link to their heading and are clickable in the exported PDF (in addition to the PDF bookmarks/outline shown in a reader's sidebar).
All standard Obsidian callout types are supported with their colors and icons:
note, abstract/summary/tldr, info, tip/hint/important, success/check/done, question/help/faq, warning/caution/attention, failure/fail/missing, danger/error, bug, example, quote/cite
Nested callouts are supported. Custom callouts from the Callout Manager plugin are also supported (colors via CSS custom properties) — custom icons are not carried over, but styling (color, background) is preserved.
Settings → Rhino PDF Export:
npm install
npm run dev # watch mode
npm run build # production
src/
├── main.ts # Entry point, commands and context menus
├── types.ts # PdfTheme, DocConfig, CustomFont, PluginSettings
├── themes.ts # Built-in themes + factory + duplication
├── settings.ts # Settings tab (theme editor, JSON import/export)
├── modal.ts # Export modal with live preview
├── batch.ts # Batch export (full folder)
├── doc-config-ui.ts # "This document" overrides section, shared by both modals
├── frontmatter.ts # rhino-pdf validation + theme resolution
├── export.ts # Shared note → PDF pipeline + asset cache
├── font-meta.ts # sfnt/woff/woff2 parser: family, weight, style
├── font-picker.ts # Vault font autocomplete + folder import
├── render.ts # HTML + CSS Paged Media generation
├── pdf.ts # Electron BrowserWindow + printToPDF
└── vendor/
├── paged.polyfill.txt # paged.js v0.4.3 bundled
├── inter.css # Inter, woff2 inlined as data URIs
└── jetbrains-mono.css # JetBrains Mono, same
scripts/
└── vendor-fonts.mjs # Regenerates the two vendored stylesheets
Fonts are vendored, not fetched. node scripts/vendor-fonts.mjs re-downloads Inter and JetBrains Mono from Google Fonts, keeps the latin and latin-ext subsets, and inlines each woff2 as a data URI. Both are variable fonts, so one @font-face per subset carries a font-weight range.
Inspired by Better Export PDF.
This plugin bundles and redistributes the following MIT-licensed libraries:
And the following typefaces, under the SIL Open Font License 1.1:
Their full license texts are reproduced in THIRD_PARTY_NOTICES.md.
GPLv3