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("処理が完了しました。")