PDFファイルのパスワードをパスワードなしの状態で保存しておく方法


Posted on 2021/8/21 at 2:30

Update on 2022/3/22 at 1:18


私の職場では2021年4月から給料明細がPDF化されてメールで送信されるようになりました。

入社してから給料明細を捨てないでとってあるので、PDFをフォルダにまとめて保存していたのですが、ファイルを開くのに毎回パスワードを入力しなくてはいけません。

パスワードを解除した状態で保存する方法について調べていたのですが、結論から言うと無料版のAdobe Acrobat Readerではできないため、Chromeの 印刷機能のうち「PDFに保存」する方法で、パスワードを解除して保存することができました。

フリーソフトなどでもパスワードを解除できそうでしたが、ダウンロードとインストール作業が面倒そうだったため、Chromeでやってみることに。 私のPCにはChromeがインストール済みだったので、この方法だとたった4ステップで完了し最も簡単でした。Chrome使用している人には手軽でおすすめです。

しかし、簡単とはいえ毎回パスワードを入力するのが面倒になってきてしまい、結局自分でプログラムを書いて使用しています。せっかく書いたのでそちらの方法についても 解説していきます。

目次
1. Chromeを利用してPDFのパスワードを解除する方法
2. JavaでPDFのパスワードを解除する方法

Chromeを利用してPDFのパスワードを解除する方法

ChromeでPDFファイルを開く

目的のPDFファイルを右クリックして「プログラムから開く」、「Google Chrome」を選択して、ChromeでPDFファイルを開きます。

パスワードの入力

PDFファイルに設定されているパスワードを入力して、ファイルを開きます。

印刷画面を開く

Chromeの右上にある印刷ボタンをクリックします。

PDFを保存する

印刷設定が表示されたら、送信先に「PDFに保存」を選択して「保存」をクリックします。保存先を指定して保存すれば次回からはパスワードの 入力なしでファイルを開くことができます。

JavaでPDFのパスワードを解除する方法

ライブラリの準備

Javaの標準機能だけでは実装が難しそうなので何か便利なライブラリがないかと調べてみた結果、 「PDFBox」というフリーライブラリに関する情報が多かったため、これを利用してみます。

今回はPDFのパスワードの解除と設定が目的なので、PDFBox本体とcommons-loggingだけあれば問題ないので、 以下のライブラリをダウンロードしてクラスパスに追加しておきます。2022/01/31時点での最新バージョンは以下です。

pdfbox-app-3.0.0-alpha2.jar

commons-logging-1.2-bin.zip

サンプルコード

JFileChooserでPDFを選択し、パスワードを入力(InputPasswordDialogクラス)して再度JFileChooserを使用してPDFを保存します。

PDFUtil.java

unlock(): パスワードを解除して別ファイルとして保存することができます。

protect(): PDFファイルにパスワードを設定し保存することができます。

		import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.swing.JFileChooser;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;

public class PDFUtil {

	public static void main(String[] args) {
		new PDFUtil().unlock();
	}

	public void unlock() {
		PDDocument doc = null;
		FileInputStream is;
		try {
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
		        if ("Windows".equals(info.getName())) {
		            UIManager.setLookAndFeel(info.getClassName());
		            break;
		        }
		    }
			JFileChooser filechooser = new JFileChooser(".");
			FileFilter filter = new FileNameExtensionFilter("PDFファイル", "pdf");
			filechooser.addChoosableFileFilter(filter);
			filechooser.setFileFilter(filter);
		    int selected = filechooser.showOpenDialog(null);
		    if (selected != JFileChooser.APPROVE_OPTION)
		    	return;
		    File input = filechooser.getSelectedFile();
			is = new  FileInputStream(input);
			try {
				doc = Loader.loadPDF(is);
			} catch (InvalidPasswordException e) {
				InputPasswordDialog passDialog = new InputPasswordDialog();
				String password = passDialog.showDialog(null);
				is = new  FileInputStream(input);
				doc = Loader.loadPDF(is, password);
			}
			if (filechooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION)
				return;
			doc.setAllSecurityToBeRemoved(true);
			doc.save(filechooser.getSelectedFile());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (doc != null)
					doc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void protect() {
		PDDocument doc = null;
		FileInputStream is;
		try {
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
		        if ("Windows".equals(info.getName())) {
		            UIManager.setLookAndFeel(info.getClassName());
		            break;
		        }
		    }
			JFileChooser filechooser = new JFileChooser(".");
			FileFilter filter = new FileNameExtensionFilter("PDFファイル", "pdf");
			filechooser.addChoosableFileFilter(filter);
			filechooser.setFileFilter(filter);
		    int selected = filechooser.showOpenDialog(null);
		    if (selected != JFileChooser.APPROVE_OPTION)
		    	return;
			is = new  FileInputStream(filechooser.getSelectedFile());
			doc = Loader.loadPDF(is);
			InputPasswordDialog passDialog = new InputPasswordDialog();
			String password = passDialog.showDialog(null);
			AccessPermission ap = new AccessPermission();
			StandardProtectionPolicy spp = new StandardProtectionPolicy("", password, ap);
			spp.setEncryptionKeyLength(128);
			doc.protect(spp);
			filechooser.showSaveDialog(null);
			doc.save(filechooser.getSelectedFile());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (doc != null)
					doc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
		

InputPasswordDialog.java

パスワード入力用ダイアログを表示するクラス

		import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;

public class InputPasswordDialog extends JDialog {

	private String password;

	public InputPasswordDialog() {
		setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setSize(500, 120);
		setTitle("パスワードの入力");
	}

	public String showDialog(Window parent) {
		setLocationRelativeTo(parent);
		JLabel label = new JLabel("パスワードを入力してください: ");
		final JPasswordField passField = new JPasswordField(15);
		passField.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					if (passField.getPassword().length > 0) {
						char[] pass = passField.getPassword();
						password = new String(pass);
						dispose();
					}
				}
			}
		});
		Container c = getContentPane();
		c.setLayout(new BorderLayout());
		JPanel center = new JPanel();
		center.setLayout(new FlowLayout(FlowLayout.LEADING));
		center.add(label);
		center.add(passField);
		JPanel south = new JPanel();
		south.setLayout(new FlowLayout(FlowLayout.TRAILING));
		JButton ok = new JButton("O K");
		ok.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				char[] pass = passField.getPassword();
				password = new String(pass);
				dispose();
			}
		});
		JButton cancel = new JButton("Cancel");
		cancel.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				password = null;
				dispose();
			}
		});
		south.add(ok);
		south.add(cancel);
		c.add(center, BorderLayout.CENTER);
		c.add(south, BorderLayout.SOUTH);
		setVisible(true);
		return password;
	}
}
		

実行結果

まずはprotect()メソッドでPDFファイルをパスワードで保護します。

パスワードを設定するファイルの選択

パスワードを設定するファイルを選択します。

パスワードの設定

設定するパスワードを入力します。

保護したファイルの保存先を選択

パスワードで保護したPDFファイルの保存先とファイル名を選択します。今回は「protect.pdf」として保存しました。

PDFファイルを開く

保存したPDFファイルを開くとAcrobatReaderが起動し、パスワードの入力を求められます。先程設定したパスワードを入力するとファイルが開けます。


次にprotect()で保護したPDFファイルをunlock()メソッドでパスワードを解除して、そのまま保存してみます。

パスワードを解除するファイルの選択

パスワードを解除するファイルを選択します。

パスワードの入力

パスワードを入力します。

ファイルの保存先を選択

パスワードを解除したPDFファイルの保存先とファイル名を選択します。今回は「unlock.pdf」として保存しました。

PDFファイルを開く

保存したPDFファイルを開くとAcrobatReaderが起動し、パスワードの入力なしでファイルが開けるようになります。

まとめ

今回は汎用性を持たせるためにFileChooserやパスワードの入力画面を用意しましたが、私は同じパスワードで保護されたPDFをまとめて解除して 保存したいため、あるフォルダに入れたPDFをまとめて処理しています。

関連記事

【JAVA】PDFBoxで複数ページあるPDFを画像に変換する

複数ページあるPDF文書をフリーライブラリであるPDFBoxを使用して、画像に変換する方法を解説します。サンプルコードあり。