【Python】Python ~ PDF ~

■ はじめに

前々からやろうと思っていたPythonのPDF化について
纏めてみる。
(半自動的にドキュメントを作れるようにしておくために)

目次

【1】PythonでのPDF化
【2】インストール
【3】API仕様
 1)cell
 2)image
【4】サンプル
 例1:Hello World
 例2:With DOT
 例3:クラス化

【1】PythonでのPDF化

* いくつかライブラリがありそうだが、以下を扱う
 + PyFPDF (Python Free-PDF)

https://pyfpdf.readthedocs.io/en/latest/

【2】インストール

pip install fpdf

【3】API仕様

* 分からなかったら、以下から漁ればよさげ

https://pyfpdf.readthedocs.io/en/latest/ReferenceManual/index.html

1)cell

fpdf.cell(w, h = 0, txt = '', border = 0, ln = 0, 
          align = '', fill = False, link = '')

https://pyfpdf.readthedocs.io/en/latest/reference/cell/index.html

2)image

fpdf.image(name, x = None, y = None, w = 0, h = 0, type = '', link = '')

https://pyfpdf.readthedocs.io/en/latest/reference/image/index.html

【4】サンプル

例1:Hello World

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()

pdf.set_font("Arial", size=25)
# create a cell
pdf.cell(200, 10, txt="Hello world!", ln=1, align='C')
pdf.cell(200, 10, txt="Hi, PDF!", ln=2, align='C')
pdf.output("output.pdf")

print("Done")

例2:With DOT

import graphviz
from fpdf import FPDF
# 画像処理ライブラリPillow(PIL)
#  => pip install Pillow
from PIL import Image


pdf = FPDF()
pdf.add_page()

pdf.set_font("Arial", size=25)
# create a cell
pdf.cell(200, 10, txt="Hello world!", ln=1, align='C')
pdf.cell(200, 10, txt="Hi, PDF!", ln=2, align='C')

# DOT
graph = graphviz.Source.from_file('sample.dot', format='png')
graph.render(filename="output1", cleanup=True)
dot_image = Image.open('output1.png')
width, height = dot_image.size
# この辺のサイズは、まじめに計算した方がいい
pdf.image('output1.png', x=20, y=pdf.get_y(), w=30)

pdf.output("output.pdf")

print("Done")

例3:クラス化

import graphviz
from fpdf import FPDF
from PIL import Image


class PdfCreator():
  def __init__(self):
    self.pdf = FPDF()
    self.pdf.add_page()
    self.pdf.set_font("Arial", size=10)

  def add_text(self, text):
    self.pdf.cell(200, 10, txt=text, ln=1, align='L')

  def add_dot_image(self, dot):
    # DOT
    format = 'png'
    graph = graphviz.Source.from_file(dot, format=format)
    file_name = 'temp1'
    graph.render(filename=file_name, cleanup=True)
    image_file = f'{file_name}.{format}'
    dot_image = Image.open(image_file)
    width, height = dot_image.size
    pdf_image_width = self.calculate_width(
      width, height, self.pdf.get_y())
    self.pdf.image(image_file, x=20, y=self.pdf.get_y(), w=pdf_image_width)

  def calculate_width(self, width, height, y):
    # width:height = x : y
    #  => x  = (width * y) / height
    return (int)((width * y) / height)

  def output_pdf(self, output):
    self.pdf.output(output)

if __name__ == "__main__":
  pdf = PdfCreator()
  pdf.add_text('Add DOT Image:')
  pdf.add_dot_image('demo1.dot')
  pdf.output_pdf('output_ex.pdf')
  print("Done")

demo1.dot

digraph {
    graph [rankdir=LR]
    node [fontname="MS Gothic"]
    table1
    table2
    table3
    table4
    table1 -> table2
    table2 -> table3
    table2 -> table4
    # ADD HERE, IF YOU WANT
    table2[shape = box, style = "dashed,rounded,filled" color = "#9BD4A3"];
}

参考文献

https://pymori.xyz/fawbgg4yx8/
https://blog.imind.jp/entry/2020/03/07/230101

関連記事

Python ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2014/08/07/231242
Python ~ 基本編 / 文字列 ~
https://dk521123.hatenablog.com/entry/2019/10/12/075251
Python + DOT言語で図作成するには
https://dk521123.hatenablog.com/entry/2023/06/14/174104
Python ~ 画像処理 / Pillow ~
https://dk521123.hatenablog.com/entry/2023/07/10/000000