0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonでPDF差分検出

Posted at

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の差分検出からレポート作成までを自動化しました。この方法を応用すれば、業務の効率化が図れます。ぜひプロジェクトで活用してみてください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?