adbird(広告鳥) 備忘録

PythonでPDFを結合・ページ番号付け・ブックマーク(しおり)付けのスクリプト

python でPDFを結合して、ページ番号とブックマーク(しおり)を付けるスクリプト

結合前のpdfには「001_」「002_」という連番とアンダーバーがついている前提。

いつものようにChatGPTに聞きまくって作った。

いろいろ試行錯誤してきたけど、完成版ではなかろうか。一瞬で結合・ページ番号付け・ブックマーク(しおり)付けが終わる。

PyMuPDFが入っていなければ、インストール。

pip install PyMuPDF

以下、スクリプト

import os
import csv
import glob
import fitz  # PyMuPDF

# 最終ファイル_ブックマーク付き.pdfがあれば削除。スクリプト再実行した際の考慮。
if os.path.exists("最終ファイル_ブックマーク付き.pdf"):
    os.remove("最終ファイル_ブックマーク付き.pdf")

# 結合後の各PDFファイルの開始ページを取得する
def get_start_pages(pdf_files):
    start_pages = []
    current_page = 0
    for pdf_file in pdf_files:
        with fitz.open(pdf_file) as doc:
            start_pages.append(current_page)
            current_page += len(doc)
    return start_pages

# 冒頭の連番を削除する
def remove_prefix(text):
    parts = text.split('_')  # アンダーバーで分割して連番を取得
    if len(parts) > 1 and parts[0].isdigit():  # 分割した最初の部分が数字であれば連番として扱う
        return '_'.join(parts[1:])  # 連番を削除して連結
    return text

# bookmarks.csvファイルに出力する
def write_bookmarks_csv(pdf_files, start_pages, 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):
            title = os.path.splitext(remove_prefix(pdf_files[idx]))[0]  # 冒頭の連番を削除して拡張子を除去
            writer.writerow([title, start_page, "parent=parent"])
    print(f"CSVファイル '{csv_file}' 出力完了")

# 結合
def merge_pdfs(pdf_files, output_pdf="結合ファイル.pdf"):
    pdf_writer = fitz.open()
    for pdf_file in pdf_files:
        with fitz.open(pdf_file) as doc:
            pdf_writer.insert_pdf(doc)
    pdf_writer.save(output_pdf)
    print("PDFの結合完了")


# ページ番号をつける(デフォルトでの基準点は左下。ただし、左上、右上にも変更可能。)
def add_page_numbers(input_pdf, output_pdf, x_mm=105, y_mm=7):
    x_pt = x_mm * 72 / 25.4  # 1 mm = 72/25.4 points
    y_pt = y_mm * 72 / 25.4
    with fitz.open(input_pdf) as pdf_reader:
        for page_number in range(len(pdf_reader)):
            page = pdf_reader[page_number]
            page_width = page.rect.width
            page_height = page.rect.height
            text = str(page_number + 1)
            font_size = 10
            page.insert_text((x_pt, page_height - y_pt), text, fontsize=font_size, color=(0, 0, 0)) #基準点が左下。
           # page.insert_text((x_pt,y_pt), text, fontsize=font_size, color=(0, 0, 0)) #基準点が左上。
           # page.insert_text((page_width - x_pt, y_pt), text, fontsize=font_size, color=(0, 0, 0)) #基準点が右上。
        pdf_reader.save(output_pdf)
    print("ページ番号付け完了")

# ページ番号をつける ※serifフォントにする場合。フォントファイルへのパス指定が必要。
# def add_page_numbers(input_pdf, output_pdf, x_mm=105, y_mm=7):
#     x_pt = x_mm * 72 / 25.4  # 1 mm = 72/25.4 points
#     y_pt = y_mm * 72 / 25.4
#     font_path = "/usr/share/fonts/opentype/ipaexfont-mincho/ipaexm.ttf"  # serifフォントファイルのパスを指定する
#     with fitz.open(input_pdf) as pdf_reader:
#         for page_number in range(len(pdf_reader)):
#             page = pdf_reader[page_number]
#             page_width = page.rect.width
#             page_height = page.rect.height
#             text = str(page_number + 1)
#             font_size = 10
#     ## フォントserif
#             font_name = "serif"
#             page.insert_text((x_pt, page_height - y_pt), text, fontsize=font_size, color=(0, 0, 0), fontname=font_name, fontfile=font_path) #基準点が左下。
#            # page.insert_text((x_pt,y_pt), text, fontsize=font_size, color=(0, 0, 0), fontname=font_name, fontfile=font_path) #基準点が左上。
#            # page.insert_text((page_width - x_pt, y_pt), text, fontsize=font_size, color=(0, 0, 0), fontname=font_name, fontfile=font_path) #基準点が右上。
#         pdf_reader.save(output_pdf)
#     print("ページ番号付け完了")

# しおり(ブックマーク)をつける
def add_bookmarks(input_pdf, output_pdf="最終ファイル.pdf"):
    bookmarks_csv = "bookmarks.csv"
    with open(bookmarks_csv, mode='r', newline='') as f:
        reader = csv.reader(f)
        bookmarks = list(reader)

    with fitz.open(input_pdf) as pdf_reader:
        toc = []
        for bookmark in bookmarks:
            title, page_num, parent = bookmark
            page_num = int(page_num)
            toc.append([1, title, page_num + 1])
        pdf_reader.set_toc(toc)
        temp_output = "temp_最終ファイル.pdf"
        pdf_reader.save(temp_output)
        os.rename(temp_output, output_pdf)
    print("ブックマーク追加完了")

def main():
    pdf_files = sorted(glob.glob("*.pdf"))
    start_pages = get_start_pages(pdf_files)
    write_bookmarks_csv(pdf_files, start_pages)
    merge_pdfs(pdf_files, output_pdf="結合ファイル.pdf")
    add_page_numbers("結合ファイル.pdf", "最終ファイル.pdf")
    add_bookmarks("最終ファイル.pdf", "最終ファイル_ブックマーク付き.pdf")

if __name__ == "__main__":
    main()

os.remove("bookmarks.csv")
os.remove("結合ファイル.pdf")
os.remove("最終ファイル.pdf")
print("処理が完了しました。")