以前、以下のような記事を書いたが、この方法だと別途「ページ番号.pdf」と「bookmarks.txt」が必要だった。
python と pdftk でPDFを結合し、ページ番号をつけ、しおりをつけるスクリプト - adbird(広告鳥) 備忘録
今回は、「ページ番号.pdf」と「bookmarks.txt」を用意しなくても良い方法。
えぇ、今回もChat GPTさんに聞きまくりました(これやるにはどんなスクリプト書けばいい?→こうです→こんなエラーが出たよ→こうでした→こんなエラーが…の繰り返し)。
環境はUbuntu。
ディレクトリ構造
├── 001_test.pdf
├── 002_テスト.pdf
├── 003_てすと.pdf
├── addbookmarks.py
├── getpagenum.py
└── mergepdf.py
pdfファイル名は「001_」というように、3ケタの連番+半角アンダーバーを必ずつける。
getpagenum.py、mergepdf.py、addbookmarks.pyの順番にスクリプトを実行していく。
getpagenum.py
pdfファイルを結合した際の、各pdfがどのページに位置づけられるかを取得。また、ファイル名を取得してbookmarks.csvに出力するスクリプト。
import csv
import glob
from PyPDF4 import PdfFileReader
# PDFファイルのリストを取得する
pdf_files = sorted(glob.glob("*.pdf"))
# 結合後の各PDFファイルの開始ページを取得する
start_pages = []
current_page = 1
for pdf_file in pdf_files:
with open(pdf_file, "rb") as f:
reader = PdfFileReader(f)
start_pages.append(current_page)
current_page += reader.numPages
# bookmarks.csvファイルに出力する
csv_file = "bookmarks.csv"
with open(csv_file, mode='w', newline='') as f:
writer = csv.writer(f)
for idx, start_page in enumerate(start_pages):
writer.writerow([f"1",pdf_files[idx], start_page])
print(f"CSVファイル '{csv_file}' に出力しました。")
端末で
python3 getpagenum.py
とすると、「bookmarks.csv」が生成される。
mergepdf.py
PDFの結合とページ番号の追加。
import os
import io
from PyPDF4 import PdfFileMerger, PdfFileReader, PdfFileWriter
from reportlab.pdfgen import canvas
# カレントディレクトリを取得
current_directory = os.getcwd()
# 結合後のPDFファイル名
output_pdf = os.path.join(current_directory, "input.pdf")
# ワイルドカードを使用してPDFファイルをリストアップし、ファイル名のソートを行う
pdf_files = sorted([os.path.join(current_directory, file) for file in os.listdir(current_directory) if file.endswith('.pdf')])
# PdfFileMergerオブジェクトを作成
pdf_merger = PdfFileMerger()
# PDFファイルを結合
for pdf_file in pdf_files:
with open(pdf_file, 'rb') as file:
pdf_merger.append(file)
# 結合したPDFを一時的なファイルに保存
temp_merged_pdf = os.path.join(current_directory, "temp_merged_file.pdf")
with open(temp_merged_pdf, 'wb') as file:
pdf_merger.write(file)
# ページ番号を追加する関数
def add_page_numbers(input_pdf, output_pdf):
with open(input_pdf, 'rb') as file:
pdf_reader = PdfFileReader(file)
pdf_writer = PdfFileWriter()
# 全ページの数を取得
num_pages = pdf_reader.numPages
# ページ番号を追加して新しいPDFを作成
for page_number in range(num_pages):
page = pdf_reader.getPage(page_number)
packet = io.BytesIO()
can = canvas.Canvas(packet)
text = str(page_number + 1)
can.drawString(565, 810, text) #ページ番号の位置(左下からの位置。単位はpt。)
can.save()
packet.seek(0)
new_page = PdfFileReader(packet)
page.mergePage(new_page.getPage(0))
pdf_writer.addPage(page)
# 新しいPDFを保存
with open(output_pdf, 'wb') as output_file:
pdf_writer.write(output_file)
# ページ番号を追加
add_page_numbers(temp_merged_pdf, output_pdf)
# 一時的な結合ファイルを削除
os.remove(temp_merged_pdf)
print("PDFの結合とページ番号の追加が完了しました。")
端末で
python3 mergepdf.py
とすると、「input.pdf」が生成される。Windowsは python3 ではなく、python かも(以下、同じ)。
addbookmarks.py
bookmarks.csv 中の、ファイル名=ブックマーク名の「001_」から「050_」までの連番を削除。
bookmarks.csvをpdftkのブックマーク書式に変換して、上記のinput.pdfにブックマークをつけて、output.pdfに出力。
import csv
import re
import subprocess
# ファイル名
input_file = 'bookmarks.csv'
output_file_txt = 'output.txt'
output_file_pdf = 'output.pdf'
# ブックマーク書式のテンプレート
bookmark_template = "BookmarkBegin\nBookmarkTitle: {title}\nBookmarkLevel: 1\nBookmarkPageNumber: {page}\n"
# 連番のパターン
number_pattern = r'\d{3}_'
# 連番の最大値
max_number = 50
# CSVファイルの読み込み
with open(input_file, 'r', newline='', encoding='utf-8') as csv_in:
reader = csv.reader(csv_in)
# ブックマーク書き出し用のテキストファイルを作成
with open(output_file_txt, 'w', encoding='utf-8') as txt_out:
for row in reader:
# ファイル名から連番を削除
file_name = row[1]
# 連番を削除
file_name = re.sub(number_pattern, '', file_name)
# ページ番号
page_number = row[2]
# ページ番号が連番の最大値を超えている場合は調整
page_number = min(int(page_number), max_number)
# ブックマーク書式にフォーマットして書き出し
bookmark_data = bookmark_template.format(title=file_name, page=page_number)
txt_out.write(bookmark_data)
# pdftkを使ってPDFにブックマークを追加
subprocess.run(["pdftk", "input.pdf", "update_info_utf8", output_file_txt, "output", output_file_pdf, "verbose"])
print("処理が完了しました。")
端末で
python3 addbookmarks.py
とすると、「output.pdf」が生成される。完成。