見出し画像

PDFから文字だけを消すプログラム(ソースコード公開)

こんにちは!
ノーリーです。ChatGPT使ってますか?

本にある文字を消して挿絵や写真だけにしたい、って時ありませんか?
生成AIのClaude先生に手伝ってもらって、さくっとつくってみました。
着手から完成まで40分。
クロさん様様です。

この記事は、大阪のIT専門学校「清風情報工科学院」の校長・平岡憲人(ノーリー)がお送りします。


PDFから文字だけを消すPythonプログラムの紹介

このPythonプログラムは、PDFファイルから文字のみを削除し、元の画像やレイアウトはそのままに保持するユニークなプログラムです。主な特徴は以下の通りです:

  1. 選択的テキスト削除: PDFの文字部分のみを白く塗りつぶし、画像や図表などの非テキスト要素はそのまま残します。

  2. レイアウト保持: 元のPDFのページ構成や要素の配置を維持したまま、テキストのみを除去します。

  3. Google Cloud Vision API活用: テキスト検出に高精度なGoogle Cloud Vision APIを使用し、正確な文字領域の特定を実現しています。

  4. ページ下部の保護: ページ番号などの重要情報を守るため、各ページの下部2cm分は処理対象から除外しています。

  5. 使いやすいインターフェース: tkinterを使用したGUIで、処理したいPDFファイルを簡単に選択できます。

  6. 出力ファイル名の自動生成: 既存のファイルを上書きしないよう、自動的にユニークなファイル名を生成します。

左の本が右のようになります

このプログラムは、機密文書の匿名化、デザインテンプレートの作成、または視覚的な情報のみを残したい場合など、様々な用途に活用できます。マンガの吹き出しの文字だけ消すというような用途にも使えるだろうと思います。PDFの構造を保ちながら文字情報だけを除去するという特殊なニーズに応える、効果的なツールです。

ソースコード

必要な環境

このプログラムを実行するには、Pythonに以下のライブラリをインストールする必要があります。pipを使用して以下のコマンドを実行してください:

pip install google-cloud-vision
pip install pdf2image
pip install opencv-python-headless
pip install Pillow

注意:
pdf2imageライブラリを使用するには、システムにPoppler(PDFレンダリングライブラリ)がインストールされている必要があります。Popplerのインストール方法は、使用しているオペレーティングシステムによって異なります。次の記事を参考になさって下さい。

また、Google Cloud Vision APIを使用するためには、Google Cloudアカウントの設定と認証情報の準備が必要です。Google Cloud Consoleで適切な設定を行い、認証情報(JSONキーファイル)をダウンロードして環境変数の「GOOGLE_APPLICATION_CREDENTIALS」に設定してください。

これらの準備が整えば、プログラムを実行する環境が整います。

プログラム

Pythonで書かれています。
Windowsにて動作確認しました。

import os
import io
from google.cloud import vision
from pdf2image import convert_from_path
import cv2
import numpy as np
from PIL import Image
import tkinter as tk
from tkinter import filedialog

# Google Cloud Visionクライアントを初期化
client = vision.ImageAnnotatorClient()

def generate_unique_filename(base_path):
    directory, filename = os.path.split(base_path)
    name, ext = os.path.splitext(filename)
    counter = 1
    while os.path.exists(base_path):
        base_path = os.path.join(directory, f"{name}({counter}){ext}")
        counter += 1
    return base_path

def remove_text_from_pdf(input_pdf_path):
    base_output_path = os.path.splitext(input_pdf_path)[0] + '_TextOnly.pdf'
    output_pdf_path = generate_unique_filename(base_output_path)
    images = convert_from_path(input_pdf_path)
    processed_images = []

    for i, image in enumerate(images):
        # PILイメージをOpenCV形式に変換
        cv_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
        height, width = cv_image.shape[:2]

        # Google Cloud Visionにイメージを送信
        success, encoded_image = cv2.imencode('.png', cv_image)
        content = encoded_image.tobytes()
        image_vision = vision.Image(content=content)
        response = client.document_text_detection(image=image_vision)

        # ページ下部2cmを計算(300 DPIを仮定)
        bottom_margin = int(2 * 300 / 2.54)  # 2cm in pixels

        # テキスト領域を白で塗りつぶす(ページ下部2cm以外)
        for page in response.full_text_annotation.pages:
            for block in page.blocks:
                for paragraph in block.paragraphs:
                    vertices = paragraph.bounding_box.vertices
                    top_left = (vertices[0].x, vertices[0].y)
                    bottom_right = (vertices[2].x, vertices[2].y)
                    
                    if bottom_right[1] < height - bottom_margin:
                        cv2.rectangle(cv_image, top_left, bottom_right, (255, 255, 255), -1)

        # OpenCV形式をPIL形式に戻す
        processed_image = Image.fromarray(cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB))
        processed_images.append(processed_image)

    # 処理済み画像をPDFとして保存
    processed_images[0].save(output_pdf_path, save_all=True, append_images=processed_images[1:])
    print(f"処理が完了しました。出力ファイル: {output_pdf_path}")

# Tkinterのルートウィンドウを作成
root = tk.Tk()
root.withdraw()  # メインウィンドウを表示しない

# ファイル選択ダイアログを表示
input_pdf_path = filedialog.askopenfilename(
    title="処理するPDFファイルを選択してください",
    filetypes=[("PDFファイル", "*.pdf")]
)

# ファイルが選択された場合のみ処理を実行
if input_pdf_path:
    remove_text_from_pdf(input_pdf_path)
else:
    print("ファイルが選択されませんでした。")

# Tkinterのメインループを終了
root.destroy()

プロンプト

このプログラムを生み出したプロンプトは次のようなものでした:

  • 元のテキストのレイアウトはそのままにして、文字の部分を消して、文字が消えて絵が元の場所にあるというファイルが作りたいんだ。

  • 元のファイルはPDFで、そのPDFの全頁について、レイアウトを保ったまま、テキストを除去する。ただしページ番号があるので、ページの下部2センチにあるテキストは除去しない。出来上がったファイルは再びPDFファイルにして、ファイル名_TextOnly.pdf としたい。作業ファイルは消去しないこと。

  • PDFファイルはダイアログを出してユーザーに選択させるようにして。

  • ほとんど絵が消えてしまっている。Google Cloud Vision使っていいので精度上げて

  • 出力ファイルと同じファイル名のものがあれば、ファイル名(n).pdf というような連番にして

Claude先生が出すプログラムの精度が上がり、私は1行もコードを書きませんでした。Cursor上で順に上のようなプロンプトを唱えただけです。
これまで、Cursorの「Apply」という機能を使ったことがなかったんですが、今回はじめて本格的に使いました。便利です。Cursorの右側ペイン(Chatペイン)で提案されたコードをエディタに反映するという意味だったんですね。それまでは、ずっとコピペしていたんですよ。

使用例

基本的にどんなPDFファイルでも適用できると思います。
ページの下部2センチにあるテキストは塗りつぶしません。

自動車整備の簡単なテキストで試してみました。
外国人技能実習制度自動車整備職種安全衛生教本

まとめ

そもそも、なんで作ったかというと、学生さんに教科書を丸写し(写経)させる作業用紙をつくるためでした。
消した部分を手書きしような、というためのものです。

しかし、こういうプログラムがあっという間に書けるようになって、むっちゃうれしいです!
お使いください!

よろしければサポートお願いします! いただいたサポートはクリエイターとしての活動費に使わせていただきます! (