本記事の題名の通り、Markdown形式のファイルをPDF形式のファイルに変換する方法を調べたので、その備忘録をこちらに残します。
今回使用したのはPythonで、使用したライブラリなどは以下の通りです。
Python 3.11.1
beautifulsoup4==4.11.2
Markdown==3.4.3
pdfkit==1.0.0
使用用途は以下の通り:
-
beautifulsoup4
はMarkdown形式のファイルを一度HTMLに変換した際に、HTMLのフォーマットを整形する際に使用 -
Markdown
はMarkdown形式のファイルの中身をHTMLに変換した文字列に変換するために使用 -
pdfkit
はHTML形式のファイルをPDF形式のファイルに変換するために使用
さらに、pdfkit
でHTMLからPDFへの変換を行う際に、wkhtmltopdfを内部的に使用しているためこちらのインストールも必要です。
また、本記事を書くにあたり参考にした記事が以下の通りです。
1つ目の記事をよく参考にさせていただきました。2つ目の記事についてはHTMLからPDFに変換する際に生じたエラーを調べた際にたどり着いたものです。
本記事は以下の構成で紹介します。
- MarkdownをHTMLに変換
- HTMLをPDFに変換
- MarkdownからPDFまで一気に変換
- まとめ
1. MarkdownをHTMLに変換
Markdownファイルは拡張子*.md
で作成することができます。ここではサンプルとして、sample.md
とします。
# Markdown sample
* list1
* list2
* list3
Pythonによりこのファイルを読み取り、markdown#markdown
によりHTML形式のテキストに変換します。
以下にサンプルコードを記載(Pythonコードと同階層に作成した場合を仮定。):
from markdown import markdown
with open("sample.md", mode="r", encoding="utf-8") as f:
html_content = markdown(f.read())
with open("sample.html", mode="w", encoding="utf-8") as w:
w.write(html_content)
<h1>Markdown sample</h1>
<ul>
<li>list1</li>
<li>list2</li>
<li>list3</li>
</ul>
2. HTMLをPDFに変換
1.の工程まででMarkdown形式のファイルからHTML形式のファイルsample.html
を作成することができました。
次に、HTML形式のファイルからPDF形式のファイルを作ります。そのためにpdfkit
を使用します。ここで、注意点としてwkhtmltopdfがインストール済みであることを仮定します。環境変数を設定していない場合は、どこにインストールされているかを明示的に設定する必要があります。インストール手順に沿っていった場合は、
ENV_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
にインストール済みとなっているかと思います。
ここまで確認ができれば、後は変換のプロセスのみです。HTMLを変換する際に
- ファイルから作成する
pdfkit#from_file
- URLから作成する
pdfkit#from_url
- テキストから作成する
pdfkit#from_string
のオプションがありますが、今回はついでにHTMLファイルを作成したので1つ目のメソッドを使用しました。
pdfkit#from_file
を用いて、次のように変換を行います:
from pdfkit import configuration, from_file
# pdfkitライブラリを使用するために「wkhtmltopdf」が必要
ENV_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
config = configuration(wkhtmltopdf = ENV_PATH)
from_file("sample.html","sample.pdf",configuration =config)
ここで先ほど注意した、wkhtmltopdf
の場所をメソッド内で指定することをお忘れなく。
こちらのコードを実行し、同階層にsample.pdf
があれば成功です。
3. MarkdownからPDFまで一気に変換
1.と2.で行ったことをまとめ、それに加えてMarkdown内でコードが記載されていた場合に、シンタックスハイライトが付くように設定しました。シンタックスハイライトにはCDNを使用しており、HTML内で以下のタグを追加しています。詳しくはこちらを参照のこと。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
さて、雑ではありますが最終的な成果物がこちらです:
from pdfkit import configuration, from_file
from markdown import markdown
from bs4 import BeautifulSoup
# pdfkitライブラリを使用するために「wkhtmltopdf」が必要
ENV_PATH = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'
config = configuration(wkhtmltopdf = ENV_PATH)
options = {
'margin-top': '0.2in',
'margin-right': '0.2in',
'margin-bottom': '0.2in',
'margin-left': '0.2in',
'encoding': "UTF-8",
'enable-local-file-access': '',
}
def html_formatting(html_content):
html_text = ''
html_text += '<html lang="ja"><meta charset="utf-8"><body>'
html_text += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">'
html_text += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>'
html_text += '<script>hljs.highlightAll();</script>'
html_text += html_content
html_text += '</body></html>'
soup = BeautifulSoup(html_text, "html.parser")
return soup.prettify()
def markdown_to_pdf(input_file, output_file):
with open(input_file, mode="r", encoding="utf-8") as f:
html_content = markdown(f.read(), extensions=["extra", "nl2br", "toc", "smarty"]) # md to html string
html_text = html_formatting(html_content)
output_html = f"{output_file}_html.html"
output_pdf = f"{output_file}_pdf.pdf"
with open(output_html, "w", encoding="utf-8") as w:
w.write(html_text)
from_file(output_html,output_pdf,configuration =config, options=options) # html to pdf
if __name__ == "__main__":
markdown_file = "flet.md"
pdf_file = 'test'
markdown_to_pdf(markdown_file, pdf_file)
このコードではMarkdownファイルからHTMLおよびPDFファイルをそれぞれ出力します。
4. まとめ
MarkdownからHTMLおよびPDFファイルを出力するコードを作成することができましたが、内でのCDNがPDFでは反映されていないようなので、今後の課題として残っています。
いつか修正します。