This article is a bit different because it is not about Blender, but I thought it might be useful for some people and perhaps search engines will pick it up.
Converting markdown to PDF
I like markdown, I like it a lot. It is quick to type, and because it is text, it is easy to manage in a repo and/or create diffs and it can be read without the need for a special reader. I prefer GitHub flavoured markdown enhanced with Mermaid because I use checkboxes and flowcharts, but if you just want to mix documentation and code samples any markdown flavour is fine, and support for it in VScode is excellent.
However, even though VScode extensions like Markdown PDF make it real easy to convert markdown to a nice looking PDF document, it doesn´t give you convenient control of the styling. You can specify a css stylesheet that is applied to the intermediate HTML that is generated (Markdown-PDF uses chromium to convert HTML to the final PDF), but that stylesheet is used for all markdown documents in the workspace. You can also specify a code highlight theme (courtesy of highlight.js) but here you can only use predefined styles, not provide one of your own.
Besides styling, the generated PDF sometimes does not look exactly like the the intermediate html, likely because Markdown PDF uses the old Chromium headless shell to save the html as PDF. This might not seem like a big deal, but I like to be able to look at the html with Chrome dev tools and tweak the css. If the resulting PDF then doesn´t look exactly like the html, life becomes rather difficult. So I would like to do this conversion myself, using Chromium just like Markdown PDF does, but making sure the new head chromium is used instead of the headless shell.
Distinct steps
So I decided to break up the workflow in distinct steps and create VScode tasks for them:
-
Convert the active markdown file to an intermediate html file
(Markdown-PDF can do that for use)
-
Strip any styling and replace that with a css file of our own
This way we have full control of the layout and styling
-
[optional] Convert local image references to inline data URLs
(to get one self contained file)
-
Use playwright with headless Chromium to convert the html to PDF
All four steps/tasks can be combined in a single task for convenience, so that executing a single tasks on the active markdown file almost immediately produces a pdf without further human intervention.
Repository
I don´t have a public repository with documents that I can share that contains all the steps mentioned above, but I did create a separate public repo that contains the whole setup.
Convert markdown to PDF
This one is easy, because Markdown PDF already has this option. So all we have to do is create a VScode task, i.e. add the following bit of JSON to the tasks property in the file .vscode/tasks.json
{
"label": "Export Markdown as HTML",
"command": [
"${command:extension.markdown-pdf.html}"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
}
The way we found the id of that specific action is by going to the command pallette (Ctrl + Shift + P), searching for Markdown PDF: export (html) and then clicking on the gear icon (⚙). This will get you to the keyboard shortcuts with the command already selected, and a simple right mouse click → Copy command ID, will give you extension.markdown-pdf.html
Replace the styling
The next task definition looks like this:
{
"label": "Reformat HTML with custom CSS",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}/bin/reformathtml.py",
"${file}",
"--css",
"${workspaceFolder}/html/style.css"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
}
It calls a custom python script with the active file as an argument and an option to specify the new css file. The script can be found in the repo, but basically all it does is to strip all <style> elements
Inline images
This is an optional step, but if we want the intermediate html file that is created to be completely self contained. The task definition is again simple:
{
"label": "img2base64: active file",
"type": "shell",
"command": "python3 ${workspaceFolder}/bin/img2base64.py ${file} ${file}",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
},
"problemMatcher": []
}
It calls a custom python script with the active file as an argument and that will convert any <img> with a src attribute pointing to a local file, to an inline data uri.
Convert to PDF
The task Convert to PDF takes care of the actual conversion to PDF.
{
"label": "Convert to PDF",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}/bin/html2pdf.py",
"${workspaceFolder}/html/${fileBasenameNoExtension}.html",
"--output",
"${workspaceFolder}/pdf"
],
"group": {
"kind": "build",
"isDefault": false
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
}
It relies on a script that uses playwright package to convert the html to PDF using headless chromium.
Combining everything
The final tasks just ties those previous tasks together so that we can simply execute all of them on the active markdown file:
{
"label": "Prepare Markdown for print",
"dependsOn": [
"Export Markdown as HTML",
"Reformat cv.html with custom CSS",
"Inline images in cv.html",
"Convert to PDF"
],
"dependsOrder": "sequence",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
Notes on the VScode project
The vscode in the GitHub repository is configured to create a dev container with everything needed included. Because of this, installing all that will take a bit of time when you first build the dev container, because playwright and its dependencies are quite hefty. So have a look at the logging if you think it takes too long, but prepare for a minute or two even on a good internet connection.
The only thing you will have to configure yourself once you have the dev container running, is to make sure the Markdown PDF output folder is set to ../html because the other scripts depend on it. I have configured that in my user settings, but you might want to do that on workspace or even dev container level; just make sure to set it:
"markdown-pdf.outputDirectory": "../html"
With that all set you can test it by opening the file markdown/example.md and run