概要
このブログでは、Pythonといくつかのライブラリを使用して、テキスト挿入機能付きPDFビュアーを作成する方法を詳細に解説します。このPDFビュアーには、ドラッグアンドドロップ機能、ページナビゲーション、テキスト挿入機能、マウスカーソルの座標表示機能など、さまざまな便利な機能を搭載しています。
下記は前回作成したpdfビュアーの記事になります。
使用例
このPDFビュアーは、教育資料や業務報告書など、さまざまなPDFファイルを視覚的にナビゲートするためのツールとして利用可能です。ユーザーはファイルをアプリケーションにドラッグアンドドロップするだけでなく、ファイルダイアログを使用してPDFを開くことができ、ページごとに詳細なビューを得ることができます。また、マウスカーソルの座標をリアルタイムで確認し、特定の位置にテキストを挿入することができます。
必要なPythonライブラリとインストール方法
このプロジェクトには以下のライブラリが必要です:
tkinter
: Pythonの標準GUIツールキット。PyMuPDF
(別名fitz
): PDFファイルを操作するためのライブラリ。tkinterdnd2
: ドラッグアンドドロップ機能を実装するためのライブラリ。
これらのライブラリのインストール方法は以下の通りです:
pip install pymupdf
pip install tkinterdnd2
使用手順
- 上記のライブラリをインストールします。
- 提供されたコードをメモ帳などに丸々コピーしてPythonファイル(例:pdf_viewer.py)に保存します。
- 保存したPythonファイルを実行します。
- PDFファイルをウィンドウにドラッグアンドドロップするか、「Open File」ボタンをクリックしてファイルを選択し、PDFを表示します。
- 画面下部に表示されるナビゲーションボタンを使用して、ページ間を移動します。
- 「Add Text」ボタンをクリックしてテキストを入力し、挿入する位置を指定します。
- 必要に応じて、「Save PDF」ボタンをクリックして編集済みのPDFを保存します。
注意点
- PDFファイルのパスに特殊文字が含まれている場合、エラーが発生する可能性があります。これを避けるために、ファイルパスを適切に処理する必要があります。
- 一部のPDFファイルでは、保護されているために読み込みができないことがあります。これらのファイルは事前に保護解除が必要です。
- 文字の位置はページの高さを基準に計算されるため、Y座標を入力する際には注意が必要です。
プログラム
下記のコードをメモ帳などに丸々コピーしてPythonファイル(例:pdf_viewer.py)にしてください。
import tkinter as tk
from tkinter import filedialog, simpledialog
from tkinterdnd2 import DND_FILES, TkinterDnD
import fitz # PyMuPDF
class PDFViewer:
def __init__(self, root):
self.root = root
self.doc = None
self.current_page = 0
self.total_pages = 0
self.text = None
self.text_size = 11
self.text_x = 0
self.text_y = 0
self.page_height = 0 # ページの高さを保存する変数
self.label = tk.Label(root)
self.label.pack(fill=tk.BOTH, expand=True)
btn_frame = tk.Frame(root)
btn_frame.pack(fill=tk.X)
self.prev_btn = tk.Button(btn_frame, text="<< Previous", command=self.prev_page)
self.prev_btn.pack(side=tk.LEFT)
self.next_btn = tk.Button(btn_frame, text="Next >>", command=self.next_page)
self.next_btn.pack(side=tk.RIGHT)
open_btn = tk.Button(btn_frame, text="Open File", command=self.open_file_dialog)
open_btn.pack(side=tk.LEFT)
add_text_btn = tk.Button(btn_frame, text="Add Text", command=self.add_text_dialog)
add_text_btn.pack(side=tk.LEFT)
save_btn = tk.Button(btn_frame, text="Save PDF", command=self.save_pdf)
save_btn.pack(side=tk.RIGHT)
# ファイルパス表示用ラベル
self.file_path_label = tk.Label(root, text="No file selected")
self.file_path_label.pack(side=tk.TOP)
# 座標表示用ラベル
self.coord_label = tk.Label(root, text="X: 0, Y: 0")
self.coord_label.pack(side=tk.BOTTOM)
self.label.bind('<Motion>', self.mouse_move) # マウス移動イベントをバインド
root.drop_target_register(DND_FILES)
root.dnd_bind('<<Drop>>', self.drop)
def open_file_dialog(self):
file_path = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])
if file_path:
self.file_path_label.config(text=f"Selected file: {file_path}")
self.open_pdf(file_path)
def open_pdf(self, path):
self.doc = fitz.open(path)
self.total_pages = len(self.doc)
self.current_page = 0
self.show_page(self.current_page)
def show_page(self, page_num):
page = self.doc.load_page(page_num)
self.page_height = page.rect.height # ページの高さを取得
pix = page.get_pixmap()
if self.text:
self.add_text_to_page(page)
pix = page.get_pixmap() # Update the pixmap after adding text
img = tk.PhotoImage(data=pix.tobytes("ppm"))
self.label.config(image=img)
self.label.image = img
# Adjust window size
self.root.geometry(f"{pix.width}x{pix.height + 100}")
def add_text_dialog(self):
self.text = simpledialog.askstring("Input", "Enter the text to add:", parent=self.root)
self.text_size = simpledialog.askinteger("Input", "Enter font size:", parent=self.root, initialvalue=11)
self.text_x = simpledialog.askinteger("Input", "Enter X coordinate:", parent=self.root, initialvalue=0)
self.text_y = simpledialog.askinteger("Input", "Enter Y coordinate:", parent=self.root, initialvalue=0)
self.text_y = self.page_height - self.text_y # Y座標を反転
self.show_page(self.current_page) # Update the display with the new text
def add_text_to_page(self, page):
if not self.text:
return
# Y座標を反転してテキストを追加
page.insert_text((self.text_x, self.text_y), text=self.text, fontsize=self.text_size, color=(1, 0, 0))
def prev_page(self):
if self.current_page > 0:
self.current_page -= 1
self.show_page(self.current_page)
def next_page(self):
if self.current_page < self.total_pages - 1:
self.current_page += 1
self.show_page(self.current_page)
def mouse_move(self, event):
# ラベルに座標を表示
self.coord_label.config(text=f"X: {event.x}, Y: {self.page_height - event.y}")
def save_pdf(self):
file_path = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF files", "*.pdf")])
if file_path:
self.doc.save(file_path)
def drop(self, event):
file_path = event.data
file_path = file_path.strip('\'"{}')
self.file_path_label.config(text=f"Selected file: {file_path}")
self.open_pdf(file_path)
root = TkinterDnD.Tk()
root.title('PDF Viewer')
root.geometry('800x600')
app = PDFViewer(root)
root.mainloop()
あるいは、下のテキストファイルをダウンロードし、「.txt」を「.py」に変えることでそのまま使えます。
pdf-viewerくんv2
まとめ
このブログでは、Pythonを使用して機能豊富なPDFビュアーを開発する方法を紹介しました。GUI操作により、ユーザーフレンドリーで直感的なPDF管理ツールを簡単に作成できます。このツールは、教育、ビジネス、研究など多岐にわたる分野での文書管理とレビューに役立つでしょう。