Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How To Convert Markdown to PDF

How to convert markdown to PDF:

This post reviews several methods for converting a Markdown (.md) formatted file to PDF, from UNIX or Linux machines.

Using Pandoc:

$ pandoc How_I_got_svg-resizer_working_on_Mac_OSX.md -s -o test1.pdf

Other methods:

GRIP

http://superuser.com/questions/689056/how-can-i-convert-github-flavored-markdown-to-a-pdf I've had success using grip to display markdown in Chrome and then use Chrome's "Save as PDF" option in the Print dialog.

pip install grip  
grip your_markdown.md

grip will render the markdown on localhost:5000 ... - just edit away and refresh the browser. Print when ready.

This gave a more reliable representation than pandoc and was lighter weight than installing LaTeX (required by pandoc for pdf generation).

The print is not command line in this answer, but still found this easier/more reliable (looked 100% like Github for a long document including relatively linked images and code highlighting).

Node.js

http://superuser.com/questions/689056/how-can-i-convert-github-flavored-markdown-to-a-pdf You can also use Node.js based markdown-pdf

npm install -g markdown-pdf
markdown-pdf /path/to/markdown

NOTES:

The GRIP results look just like GitHub README pages. The Pandoc result looks like (is) LaTex format. And the Node.js result is the most original looking, but slightly harder to read than GRIP output PDF. Overall, I prefer GRIP output.

@georgegu1997
Copy link

georgegu1997 commented Jan 25, 2018

If you have Python 2 and 3 at the same time as I do, you may need to use "python3 -m grip .\filename.md" to solve the problem mentioned in pallets/flask#2543

@mzpqnxow
Copy link

mzpqnxow commented Feb 25, 2019

Check out:

pandoc README.md -o README.pdf "-fmarkdown-implicit_figures -o" --from=markdown -V geometry:margin=.4in --toc --highlight-style=espresso

More dependencies, but it makes a great ToC!

@wisnubaldas
Copy link

wisnubaldas commented Dec 2, 2019

can i convert pdf to markdown ?

@justincbagley
Copy link
Author

justincbagley commented Dec 9, 2019

Hi @wisnubaldas, you've probably figured this out by now, but you can use Pandoc. There are also some free online converters that I've played with and worked quite well, including https://pdf2md.morethan.io. And there is also a Python program, PDF to Markdown, which you can install with pip.

@justincbagley
Copy link
Author

justincbagley commented Dec 9, 2019

Thanks @georgegu1997 and @mzpqnxow for your input here!

@brilliant-ember
Copy link

brilliant-ember commented Oct 31, 2020

I get this error when I try to use it, I tried all sorts of combinations,with quotes and without, with the ./ and without, with .md at the end and without

$ markdown-pdf ./a1.md 


internal/validators.js:125
    throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
    ^

TypeError [ERR_INVALID_ARG_TYPE]: The "file" argument must be of type string. Received type object
    at validateString (internal/validators.js:125:11)
    at normalizeSpawnArguments (child_process.js:411:3)
    at spawn (child_process.js:545:16)
    at Object.execFile (child_process.js:221:15)
    at WriteStream.<anonymous> (/usr/local/lib/node_modules/markdown-pdf/index.js:117:22)
    at WriteStream.emit (events.js:203:15)
    at finishMaybe (_stream_writable.js:646:14)
    at stream._final (_stream_writable.js:624:5)
    at WriteStream._final (internal/fs/streams.js:268:3)
    at callFinal (_stream_writable.js:617:10)


@justincbagley
Copy link
Author

justincbagley commented Dec 11, 2020

Hi @brilliant-ember, did you solve this on your machine? If not, please post the a1.md file so I can test with it. Thanks.

Actually, markdown-pdf is currently not working on my new macOS machine. I get the now well-known Highlight.js v9 EOL error that follows:

justinbagley$ markdown-pdf ./convert.md 
Version 9 of Highlight.js has reached EOL and is no longer supported.
Please upgrade or ask whatever dependency you are using to upgrade.
https://github.com/highlightjs/highlight.js/issues/2877

Apparently, markdown-pdf needs to be updated to use Highlight.js v10+. If anyone is aware of additional issues/threads relevant to this, please pass them along.

For now, I would suggest sticking to pandoc or grip for Markdown to PDF conversions from the command line interface.

However, one new, non-command-line option from earlier this year that I have not tested yet is the Markdown Viewer extension for Google Chrome and Mozilla Firefox. Find it on GitHub here (from @simov). Seems worth trying.

~J

@justincbagley
Copy link
Author

justincbagley commented Dec 11, 2020

Here is the thread on Highlight.js v9 EOL errors / end of support:

highlightjs/highlight.js#2877.

@brilliant-ember
Copy link

brilliant-ember commented Dec 14, 2020

Hey, I don't think I have the file anymore but I found a workaround. I converted the markdown to html, then opened the html with chrome (web browser) then printed that page from the browser and chose the "save pdf" option instead of actually printing it, and TADAAA pdf file from my markdown.

@shinokada
Copy link

shinokada commented Feb 21, 2021

You can convert using Typora.
Typora is a markdown editor and it can convert to PDF and other formats.

image

@phseiff
Copy link

phseiff commented Apr 14, 2021

You can also use gh-md-to-html for this, which is a command line tool that can also convert markdown to pdf (despite its name).

You can install it by installing wkhtmltopdf and then installing gh-md-to-html with

pip3 install gh-md-to-html[pdf_export]

And then use

gh-md-to-html path_to_your_file.md -p \<name\>.pdf 

The -p option declares under which file name to save the resulting pdf file; the "<name>" is automatically replaced with the name of your input file.

Under to hood, gh-md-to-html converts the file to html (as the name suggests) and then from html to pdf using wkhtmltopdf.

The resulting pdf file is, in any case, styled similar to how GitHub styles their README files; if you want to disable that, you can supply the option -s false to the command, which disables the default styling.
Code blocks are properly syntax highlighted in both cases, though.

The conversion process is done partially online (using GitHub's markdown REST API); in case you don't want that, you can use pip3 install gh-md-to-html[offline_conversion] and then run gh-md-to-html with the -o OFFLINE option.

gh-md-to-html also supports inline-formulas like pandoc (but has some advantages over it when it comes to markdown-flavor-tolerance rather than looks, as describes in its README), and supports the [[_TOC_]] syntax of GitLab-flavored markdown (both features can be disabled). It also supports supplying custom CSS to style the output.

@Hexdump74
Copy link

Hexdump74 commented Aug 3, 2021

The following command will start grip on your markdown and convert it to pdf using wkhtmltopdf (and display it using evince) :
grip my.md 10000 & ; PID=$! ; sleep 1 ; wkhtmltopdf http://localhost:10000 my.pdf ; kill $PID; evince my.pdf&

@justincbagley
Copy link
Author

justincbagley commented Aug 19, 2021

Hey @Hexdump74, your suggestion looks pretty cool, thanks.

I installed wkhtmltopdf and evince (Homebrew install) on macOS and then tried to alter your code. It would not run unless I removed the ; before sleep 1 and when I ran my code it hung up during the completion on a task. What happened? It seems to have hung up on the wkhtmltopdf step, but I'm not sure how to fix it. Let me know if you have any ideas for a solution.

Here is my Terminal log:

grip Practical00_Intro_to_R.md 10000 & PID=$! ; sleep 10 ; wkhtmltopdf http://localhost:10000 Practical00_Intro_to_R.pdf ; kill $PID; evince Practical00_Intro_to_R.pdf&
[1] 85776
 * Serving Flask app "grip.app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://localhost:10000/ (Press CTRL+C to quit)
Loading pages (1/6)
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET / HTTP/1.1" 200 -  ] 10%
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /__/grip/static/octicons/octicons.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /__/grip/asset/site-d3c48f1b58ea95d9efb184fd4592b411.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /__/grip/asset/github-eabfbaded2e91939e805d1a3af34018a.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /__/grip/asset/frameworks-481a47a96965f6706fb41bae0d14b09a.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_white.png HTTP/1.1" 200 -
[=======127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_install_MASS.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_white_rnorm_plot.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_help_rnorm.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_white_dampening.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_number_seqs_full_gui.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /RStudio_mtcars.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:53] "GET /__/grip/static/octicons/octicons.woff?ef21c39f0ca9b1b5116e5eb7ac5eabe6 HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET / HTTP/1.1" 200 -  ] 88%
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /__/grip/asset/site-d3c48f1b58ea95d9efb184fd4592b411.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /__/grip/asset/frameworks-481a47a96965f6706fb41bae0d14b09a.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_white.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /__/grip/static/octicons/octicons.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_white_rnorm_plot.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /__/grip/asset/github-eabfbaded2e91939e805d1a3af34018a.css HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_help_rnorm.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_white_dampening.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_mtcars.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_number_seqs_full_gui.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /RStudio_install_MASS.png HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:55] "GET /__/grip/static/octicons/octicons.woff2?ef21c39f0ca9b1b5116e5eb7ac5eabe6 HTTP/1.1" 200 -
127.0.0.1 - - [19/Aug/2021 09:06:56] "GET /__/grip/static/favicon.ico HTTP/1.1" 200 -

~J

@justincbagley
Copy link
Author

justincbagley commented Aug 19, 2021

Hi @phseiff, sorry I didn't see this before, but I just tried it with GitHub-flavored style and without (-s false flag) and your solution for converting Markdown to PDF worked very nicely!! Thank you.

Question: Is there a way to remove the border around GitHub content but keep the other GitHub styling? (I suppose you might alter the CSS, but I'm not sure how to do that...).

Thanks again!

~J

@phseiff
Copy link

phseiff commented Aug 19, 2021

Thanks for checking it out @justincbagley, and glad you liked it!

There is no option to remove the border as of now, but you could add the following code to an additional file and supply this file via -x <file_name>:

<style>
.gist-file {
  border: none !important;
}
</style>

This will add the CSS to the generated file and remove the border around the page.

@Hexdump74
Copy link

Hexdump74 commented Aug 23, 2021

Hi @justincbagley.
Here is the output on my archlinux :

❯ grip my.md 10000 & PID=$! ; sleep 1 ; wkhtmltopdf http://localhost:10000 my.pdf ; kill $PID; evince my.pdf&
[1] 1057828
 * Serving Flask app 'grip.app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://localhost:10000/ (Press CTRL+C to quit)
Loading page (1/2)
 * Error: could not retrieve styles: [Errno 20] Not a directory: '/home/manu/.grip/cache-4.5.2'
127.0.0.1 - - [23/Aug/2021 12:13:26] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [23/Aug/2021 12:13:26] "GET /__/grip/static/octicons/octicons.css HTTP/1.1" 200 -
127.0.0.1 - - [23/Aug/2021 12:13:26] "GET /img.png HTTP/1.1" 200 -
127.0.0.1 - - [23/Aug/2021 12:13:26] "GET /__/grip/static/octicons/octicons.woff2?ef21c39f0ca9b1b5116e5eb7ac5eabe6 HTTP/1.1" 200 -
Printing pages (2/2)
Done
[2] 1057867
[1]  - 1057828 terminated  grip my.md 10000

It works, but as you can see from my logs, the md is very simple. Could you try with this simple and small md (img.png is my github avatar) :

# Notes

* first point
* second point

![](./img.png)

@galxy25
Copy link

galxy25 commented Jan 25, 2022

if you get pandoc: pdflatex: createProcess: posix_spawnp: illegal operation (Inappropriate ioctl for device)

make sure you have basictex installed and reload your shell
jgm/pandoc#7570

@hgftitanium
Copy link

hgftitanium commented Apr 19, 2022

Check out:

pandoc README.md -o README.pdf "-fmarkdown-implicit_figures -o" --from=markdown -V geometry:margin=.4in --toc --highlight-style=espresso

More dependencies, but it makes a great ToC!

Thanks for a great hint, @mzpqnxow !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment