目次
こんな感じ。
まず、下のサイトからPythonをダウンロードしてインストールする。
Welcome to Python.org
The official home of the Python Programming Language
コマンドプロンプトを開いて以下のコマンドを実行しPDFファイルを操作するのに使うpikepdfというライブラリをインストールする。
pip install pikepdf
以下のコードをコピペして適当なファイル名(例えば「EncryptPdfContent.py」とか)で適当なフォルダに保存する。このときファイルのエンコードはBOM付きのUTF-8にしておく。
#
# コマンドライン引数で指定されたPDFファイル達を暗号化する。
#
# 準備:
# 1. pipコマンドをアップデートする。
# C:\> python -m pip install --upgrade pip
# 2. パッケージpikepdfをインストールする。
# C:\> pip install pikepdf
#
#
# モジュールをインポートする。
#
import os
import sys
import shutil
import ctypes
import pikepdf
import tkinter as tk
import tkinter.messagebox as msgbox
#
# 定数を宣言する。
#
CAPTION = 'PDFファイルを暗号化'
ICON = r"C:\Program Files\MyScripts\icons\~~encryptpdf.ico"
#
# ダイアログを表示して暗号化に使用するパスワードを取得する。
#
def get_password():
# ダイアログの位置とサイズを定義する。
screen_width = root.winfo_screenwidth(); screen_height = root.winfo_screenheight()
window_width = 545; window_height = 202
root.geometry("%dx%d+%d+%d" % (window_width, window_height, (screen_width - window_width) / 2, (screen_height - window_height) / 2))
# ダイアログのリサイズを禁止する。
root.resizable(width=False, height=False)
# エスケープキー押下時の処理を登録する。
root.bind("<Escape>", lambda event: cancel_button_handler(None))
# 閉じるマークボタン押下時用のハンドラを登録する。
root.wm_protocol('WM_DELETE_WINDOW', lambda: cancel_button_handler(None))
# ガイドメッセージ用のラベルを作成する。
tk.Label(root, text='1文字以上のパスワードを入力してください。').place(x=20, y=15)
# ラベルの位置とサイズを定義する。
label_width = 10
label_left = 20
label_top = 63
# パスワード入力用のエディットボックス用のラベルを作成する。
tk.Label(root, text='パスワード:').place(x=label_left, y=label_top)
tk.Label(root, text='パスワード(確認):').place(x=label_left, y=label_top+38)
# エディットボックスの位置とサイズを定義する。
editbox_width = 36
editbox_left = 150
editbox_top = 61
# パスワード入力用のエディットボックスを作成する。
editboxPassword1 = tk.Entry(root, width=editbox_width, show='*')
editboxPassword1.place(x=editbox_left, y=editbox_top)
editboxPassword2 = tk.Entry(root, width=editbox_width, show='*')
editboxPassword2.place(x=editbox_left, y=editbox_top+38)
# エディットボックス内のリターンキー押下時の処理を登録する。
editboxPassword1.bind("<Return>", \
lambda event: editboxPassword2.focus_set() if len(editboxPassword1.get()) > 0 else ok_button_handler(event))
editboxPassword2.bind("<Return>", lambda event: ok_button_handler(event))
# エディットボックス内のエスケープキー押下時の処理を登録する。
editboxPassword1.bind("<Escape>", lambda event: cancel_button_handler(None))
editboxPassword2.bind("<Escape>", lambda event: cancel_button_handler(None))
# OKボタン押下時用のハンドラを定義する。
def ok_button_handler(event):
# エディットボックスからパスワードを取り出す。
password = editboxPassword1.get()
confirm = editboxPassword2.get()
# 空欄なら。。。
if len(password) == 0:
msgbox.showwarning(CAPTION, f'1文字以上のパスワードを入力してください。')
editboxPassword1.focus_set()
return "break"
# 一致しないなら。。。
if password != confirm:
msgbox.showwarning(CAPTION, f'パスワードが一致しません。\rもう一度入力してください。')
editboxPassword2.focus_set()
return "break"
# ここまで来たらエラーなしと判断し呼び出し元へ返る。
root.quit()
# キャンセルボタン押下時用のハンドラを定義する。
def cancel_button_handler(event):
res = msgbox.askokcancel(CAPTION, f'キャンセルされました。\r処理を中断します。', default=msgbox.CANCEL)
if res:
sys.exit(255)
return "break"
# ボタンの位置とサイズを定義する。
button_width = 10
button_left = 281
button_top = 147
# OKボタンを作成する。
buttonOK = tk.Button(root, text='OK', width=button_width)
buttonOK.place(x=button_left, y=button_top)
buttonOK.bind("<Button-1>", ok_button_handler)
buttonOK.bind("<Return>", lambda event: ok_button_handler(None))
buttonOK.bind("<Escape>", lambda event: cancel_button_handler(None))
# キャンセルボタンを作成する。
buttonCancel = tk.Button(root, text='キャンセル', width=button_width)
buttonCancel.place(x=button_left+125, y=button_top)
buttonCancel.bind("<Button-1>", cancel_button_handler)
buttonCancel.bind("<Return>", lambda event: cancel_button_handler(None))
buttonCancel.bind("<Escape>", lambda event: cancel_button_handler(None))
# ダイアログを表示する。
root.deiconify()
# ダイアログを前面に移動してアクティブにする。
root.lift()
root.focus_force()
# パスワード入力用のエディットボックスにフォーカスをセットする。
editboxPassword1.focus_set()
# メッセージループを回す。
root.mainloop()
# パスワードを返す。
return editboxPassword1.get()
#
# メインルーチン。
#
if __name__ == '__main__':
# 例外処理。。。
try:
# 高DPI対策を行う。
ctypes.windll.shcore.SetProcessDpiAwareness(True)
# メインウインドウを作成する。
root = tk.Tk()
root.withdraw()
# ダイアログのキャプションとアイコンを設定する。
root.title(CAPTION)
if os.path.isfile(ICON):
root.iconbitmap(ICON)
# コマンドライン引数を確認する。
if len(sys.argv) == 1:
msgbox.showerror(CAPTION, f'ファイルが選択されていません。\rファイルを1件以上選択して実行してください。\r処理を中断します。')
sys.exit(255)
# 選択されたPDFファイルについて。。。
targets = set([])
for file in sys.argv[1:]:
# 指定されたファイルが存在しなければプログラムを終了する。
if not os.path.isfile(file):
msgbox.showerror(CAPTION, f'指定されたファイルが存在しないかフォルダが選択されました。\r処理を中断します。\r\r{file}')
sys.exit(255)
# 指定されたファイルの拡張子が".pdf"でなければそのファイルをスキップする。
ext = os.path.splitext(file)[1]
if ext.lower() != '.pdf':
msgbox.showwarning(CAPTION, f'指定されたファイルの拡張子が".pdf"でありません。\rこのファイルをスキップします。\r\r{file}')
continue
# PDFファイルを確認する。
with pikepdf.open(file) as org:
# PDFファイルが既に暗号化されていたら処理をスキップする。
if org.is_encrypted:
msgbox.showwarning(CAPTION, f'指定されたPDFファイルは既に暗号化されています。\rこのファイルをスキップします。\r\r{file}')
continue
# PDFファイルを処理対象に加える。
targets.add(file)
# スキップ対象とならなかったPDFファイルの数が0件の場合はプログラムを終了する。
if len(targets) == 0:
msgbox.showwarning(CAPTION, f'処理対象となるPDFファイルの数が0件です。\r処理を中断します。')
sys.exit(255)
skipped = len(sys.argv[1:]) - len(targets)
# ダイアログを表示して暗号化に使用するパスワードを取得する。
password = get_password()
# 選択されたPDFファイルについて。。。
for pdf in targets:
# PDFファイルをバックアップする。
bak = pdf + '.bak'
if os.path.isfile(bak):
res = msgbox.askquestion(CAPTION, f'PDFファイルのバックアップができません。\rバックアップファイルと同じ名前のファイルが存在しています。\rファイルを上書きしますか。\r\r{bak}', default=msgbox.NO)
if res == 'yes':
shutil.copy2(pdf, bak)
else:
shutil.copy2(pdf, bak)
# PDFファイルを暗号化する。
with pikepdf.open(pdf, allow_overwriting_input=True) as org:
org.save(pdf, encryption=pikepdf.Encryption(user=password))
# 終了メッセージを表示する。
msgbox.showinfo(CAPTION, f'すべての処理が完了しました。\r\r暗号化したファイル数: %d件\rスキップしたファイル数: %d件' % (len(targets), skipped))
# 終了する。
root.withdraw()
sys.exit(0)
# すべての例外をキャッチする。
except Exception as ex:
# もしTkinterが使えれば。。。
msgbox.showerror(CAPTION, f'例外が発生しました。\rコンソール上で起動してスタックトレースを確認して下さい。\r\r{ex}')
# 例外を表示する。
print(f'\n{ex}\n')
# スタックトレースを表示する。
from traceback import TracebackException
from traceback import StackSummary
tb = TracebackException.from_exception(ex)
summary = StackSummary.from_list(tb.stack)
print(''.join(summary.format()))
以下のようなリンク先を持つショートカットを作る。下のは、上のPythonのコードを「%ProgramFiles%\MyScripts\EncryptPdfContent.py」にコピペした場合。ショートカットは適当なファイル名(例えば「PDFファイルを暗号化」とか)に変更する。
python.exe "%ProgramFiles%\MyScripts\EncryptPdfContent.py"
作ったショートカットを以下のフォルダにコピーする。
%USERPROFILE%\AppData\Roaming\Microsoft\Windows\SendTo
PDFファイル達を選択して右クリックし表示された送るメニューから上で作ったショートカットをクリックする。パスワードを入力するダイアログが表示されるので適当に入力するとPDFファイル達が暗号化される。
以上
コメント