複数PDFファイルの連結
32145035 木村涼
2022/10/10

  はじめに

前回のブログで予告した通り、今回も前回に引き続き情報学部っぽいブログを書いていこうと思う。前回はVBScriptを用いて複数のpptxファイルを一括でpdfファイルにインポートするポログラムを紹介した。→ブログ4 ~VBScript~
 今回は複数のPDFファイルを1つにまとめるプログラムについて解説していく。このプログラムも前回と同様、スマホ教室の資料作成で使うことを前提にしたプログラムであるので、他の用途で使う際にはうまい具合に書き換えてください。


  PDFファイルの結合


皆さんは教科書や参考書などを読んでる際に、「このことはもう既に知ってるんだよな・・・次のとこまで読み飛ばすか・・・めんどくさいな・・・」という経験はないだろうか?ほとんどの市販のテキストではより多くの人々に手に取ってもらうために基礎的な内容からはじまり、段々と難しくなるように作られている。だったら自身が学びたい内容や知らない内容だけが載っているオーダーメイドのテキストを作るプログラムを作ってみよう、ということで今回紹介するプログラムはこのプロジェクトの基盤となるものである。プログラム言語はPythonを用い、主にPyPDF2というモジュールを使った。作成したソースコードは以下の通りである。




import os
import datetime
import tkinter.filedialog as filedialog
from PyPDF2 import PdfFileWriter, PdfFileReader,PdfFileMerger
from io import BytesIO
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

def insert_text_output_pdf_PyPDF2(pdf_file_path, insert_text,x,y,output_name,size):
    
    # フォントの読み込み
    pdfmetrics.registerFont(TTFont("MEIRYO", "C:/Windows/Fonts/meiryo.ttc"))
    buffer = BytesIO()
    
    # PDF新規作成
    p = canvas.Canvas(buffer, pagesize=A4)
    p.setFont("MEIRYO",size)
    
    # 挿入位置(mm指定)
    target_x, target_y = x*mm, y*mm
    p.drawString(target_x, target_y, insert_text)
    p.showPage()
    p.save()

    buffer.seek(0)
    new_pdf = PdfFileReader(buffer)
    # PDFファイルを読み込む
    existing_pdf = PdfFileReader(open(pdf_file_path, 'rb'), strict=False)
    output = PdfFileWriter()
    # 既存PDFの1ページ目を読み取る
    page = existing_pdf.getPage(0)
    # 新規PDFにマージ
    page.mergePage(new_pdf.getPage(0))
    output.addPage(page)
    # 出力名
    output_stream = open(output_name, 'wb')
    output.write(output_stream)
    output_stream.close()



if __name__ == '__main__':
    
    file_path1 = "00title.pdf"
    
    n = 1
    # x=横 y=縦
    x = 130
    y = 100
    
    # pdfファイルを選択する
    typ = [('PDFファイル', '*.pdf')]
    fle = filedialog.askopenfilenames(filetypes = typ) 
    pdf_file_merger = PdfFileMerger()
    
    # 選択されたpdfファイルを加える
    for file_name in fle:
        pdf_file_merger.append(file_name)
        
    #表紙の作成
        basename = os.path.splitext(os.path.basename(file_name))[0]
        s=PdfFileReader(file_name).getNumPages()
        file_path0 = "PyPDF0.pdf"
        insert_text_output_pdf_PyPDF2(file_path1, basename, x, y, file_path0,16)
        file_path1 = "PyPDF1.pdf"
        x += 50
        insert_text_output_pdf_PyPDF2(file_path0, "p" + str(n+1) + "~p" + str(n+s), x, y, file_path1,16)
        x -= 50
        y -= 10
        n += s
    dt = datetime.date.today()
    insert_text_output_pdf_PyPDF2(file_path1, str(dt), 10, 10, "PyPDF.pdf",12)
    # 表紙を1番前に置く
    pdf_file_merger.merge(0,"Pypdf.pdf")
    
    # pdfファイルとして書き出す
    pdf_file_merger.write('result.pdf')
    
    # 編集を終了する
    pdf_file_merger.close()
    
    os.remove("PyPDF0.pdf")
    os.remove("PyPDF1.pdf")
    os.remove("PyPDF.pdf")
	 



座標設定  プログラムを上から簡単に解説するとまずinsert_text_output_pdf_PyPDF2()という関数を定義している。この関数は指定した文書の指定した部分に文字書き加えるものである。表紙の素となるファイルとして「00title.pdf」に指定しこの表紙のコピーに、結合するPDFファイルのタイトルとそのファイルが掲載されているページ数を書き加えることで表紙を完成させている。文字の配置は右図のように左下を原点としてx,y座標設定することで文字を置く位置を調節することができる。表紙の素はこちらからどうぞ→00title.pdf このPDFファイルをプログラムと同じフォルダ内に置くことでうまく作動することができます。

結合するPDFファイルはダイアログから選択しファイルパスを取得している。もちろんそのダイアログはPDFファイルのみ表示されファイルは複数選択可能になるよう設定している。表紙を作成させると同時にPDFファイルを結合し、最後に完成した表紙を一番前に引っ付けている。簡単な処理はこれで終わりである。今回の処理ではPDFファイルに書き加える際にPDFファイルを新規作成する必要があるため、余分なpdfファイルが作成されてしまう。そのため後処理として余分な表紙のPDFファイルを削除している。
PyPDF2などのモジュールはPythonの標準ライブラリではないため、実際にこのプログラムを動かす際には事前にダウンロードする必要がある。また、おそらくSpyder上ではうまく作動しないのでコマンドプロンプトなどで動かすことをお勧めします。





最後に

座標設定

今回は複数のpdfを1つにまとめ、目次付きの表紙を張り付けるというプログラムについて紹介&説明した。正直実用することはまだできる段階ではない試作状態である。使いやすくなるようなGUIの作成や、想定外の動き(目次に収まりきらないほどの量を結合する場合など)の対応などまだまだ改良しなければならない点はある。右図のようになぜか大量にPDFファイルを結合するとページ数の一部が欠けてしまうというエラーが出ている。このブログは完成が締切ぎりぎりになってしまったのだが、その理由の1つはこのバグをどうにかしようとしていたからでもある。どなたかこのバグの解決方法に思い当たりがある方は教えていただきたいです。よろしくお願いします。





  参考文献

Python, PyPDF2でPDFを結合・分割

https://qiita.com/mototoke/items/7fc4c65305c4180521e4#%E6%

【python】既存のPDFファイルにテキストを差し込む

https://qiita.com/mototoke/items/7fc4c65305c4180521e4#%E6%96%B9%E6%B3%953

Pythonのreportlabの使い方まとめ

https://qiita.com/takahashi_you/items/8c5fb1f07db1825c67a5

Pythonで「ダイアログ」を活用してみよう!

https://www.insource.co.jp/python-gakuin/mail-backnumber/vol27.html