PythonでPDF差分検出&加工を自動化するスクリプトを作成してみた
はじめに
業務でPDFファイルの変更箇所を自動検出し、画像化してレポートを作成する必要があったため、Pythonを用いて以下の機能を実現するスクリプトを作成しました。
- PDFの差分検出とマーキング
- 差分画像のPDFへの埋め込み
- 不要なPDFの削除
- PDFの最適化
本記事では、このプロセスを実現するPythonコードを解説していきます。
使用するライブラリ
まず、スクリプトで使用する主なライブラリです。
# 必要なライブラリをインストール
pip install opencv-python pillow pdf2image fitz pikepdf
- OpenCV: 画像処理全般に使用
- Pillow: 画像変換用
- pdf2image: PDFを画像に変換する
- fitz: PDF操作用(PyMuPDFのエイリアス)
- pikepdf: PDFの最適化に使用
スクリプトの全体構成
以下がスクリプト全体の構成です。
1. PDFを画像に変換
まず、PDFをページごとに画像へ変換します。
from pdf2image import convert_from_path
def pdf_to_images(pdf_path):
"""
PDFファイルを画像に変換
"""
return convert_from_path(pdf_path)
2. 差分検出とマーキング
2つの画像の差分を検出し、差分箇所をマーキングします。
import cv2
import numpy as np
def mark_differences(image1, image2, output_path):
"""
2つの画像の差分を検出してマーキング
"""
# OpenCV形式に変換
img1 = cv2.cvtColor(np.array(image1), cv2.COLOR_RGB2BGR)
img2 = cv2.cvtColor(np.array(image2), cv2.COLOR_RGB2BGR)
# 差分計算
diff = cv2.absdiff(img1, img2)
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 30, 255, cv2.THRESH_BINARY)
# 差分箇所を囲む
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
blank_img = np.ones_like(img2) * 255 # 白背景画像
for contour in contours:
if cv2.contourArea(contour) > 0:
cv2.drawContours(blank_img, [contour], -1, (203, 192, 255), 10)
# 結果を保存
cv2.imwrite(output_path, blank_img)
return output_path
3. PNG画像をPDFに埋め込む
マーキング済みの画像を元のPDFに重ねて保存します。
import fitz
def add_images_to_pdf(pdf_path, image_paths, output_pdf_path):
"""
PNG画像をPDFに埋め込み
"""
pdf_document = fitz.open(pdf_path)
for i, image_path in enumerate(image_paths):
page = pdf_document[i]
img_rect = fitz.Rect(0, 0, page.rect.width, page.rect.height)
page.insert_image(img_rect, filename=image_path, overlay=False)
pdf_document.save(output_pdf_path)
4. 不要なPDFを削除
不要なPDFファイルを削除します。
import os
def delete_files_with_keyword(directory, keyword):
"""
指定したキーワードを含むPDFファイルを削除
"""
for filename in os.listdir(directory):
if keyword in filename and filename.endswith(".pdf"):
os.remove(os.path.join(directory, filename))
5. PDFの最適化
生成されたPDFを最適化し、空のPDFは削除します。
import pikepdf
def process_and_optimize_pdf(final_output_pdf):
"""
PDFの最適化と空ファイルの削除
"""
if os.path.exists(final_output_pdf):
with pikepdf.open(final_output_pdf) as pdf:
temp_pdf_path = final_output_pdf + "_temp"
pdf.save(temp_pdf_path, linearize=True)
os.replace(temp_pdf_path, final_output_pdf)
サンプルコードの実行例
if __name__ == "__main__":
# 入力PDFのパス
old_pdf = "old_version.pdf"
new_pdf = "new_version.pdf"
output_folder = "./output/"
# PDFを画像に変換
old_images = pdf_to_images(old_pdf)
new_images = pdf_to_images(new_pdf)
# 差分検出とマーキング
for i, (old_image, new_image) in enumerate(zip(old_images, new_images)):
output_path = f"{output_folder}/page_{i+1}_diff.png"
mark_differences(old_image, new_image, output_path)
# 差分画像をPDFに埋め込み
diff_images = [f"{output_folder}/page_{i+1}_diff.png" for i in range(len(old_images))]
add_images_to_pdf(new_pdf, diff_images, "diff_report.pdf")
まとめ
今回のスクリプトでは、PDFの差分検出からレポート作成までを自動化しました。この方法を応用すれば、業務の効率化が図れます。ぜひプロジェクトで活用してみてください!