はじめに
こんにちは!
GhostScriptをpythonで使用する機会がありましたので、今回はその中で得られた知見をまとめようと思います。
具体的にはGhostScriptを使ってPDFをJPEG画像に変換(PDF⇒JPEG変換)します。
本稿でやろうとしているPDF⇒JPEG変換は「1ページもののPDFはもちろん、複数ページあるPDFも1ページに分解してJPEG画像として保存していく」というものになります。
なぜGhostScriptなのか?
GhostScriptは公式サイトにもあるように、PostScript言語やPDFのためのインタプリタになります。
公式サイトより引用
An interpreter for the PostScript language and for PDF.
本稿でやりたいことをgoogle先生に聞いてみると、pdf2imageやPyPDF2が一般的な解決方法かと思いますが、なぜGhostScriptを使ったのかというと、理由は簡単です。
PyPDF2では変換できず、GhostScriptで変換できるPDFがあったからです笑
なお、GhostScriptの操作はこちらのサイトを参考にしています。
(このサイトでは特にpythonは使われておりません。)
http://michigawi.blogspot.com/2011/12/ghostscriptpdfjpg.html
開発環境
Windows10
python3.6.9
GhostScript 9.50
事前準備(GhostScriptのダウンロード)
今回はGhostScriptを下記からダウンロードします。
https://www.ghostscript.com/
各開発環境に合わせてダウンロードを実施してください。
この記事ではAGPLのfor Windows(64bit)を選択しています。
ダウンロードしたファイルを実行してセットアップを行ってください。
※ghostscriptはPyPIでもpipコマンドでインストール出来るようですが、本稿執筆にあたって、こちらは特に確認していません。
https://pypi.org/project/ghostscript/
やりたいこと①:PDFをページ分割
「はじめに」で説明したように複数ページあるPDFに必要な処理であり、元々1ページのPDFであれば必要ありません。
長くなるので、分割に関係あるところだけをピックアップしました。
お時間のない方は全体ソースコードもこの後の章に載せているので、そちらをご確認ください。
前提としてソースコードと同じディレクトリに「input」フォルダを作成して、そこに入力画像となるPDFファイルを置いてください。
「output_tmp」というディレクトリが自動的に作られ、ページ分割されたPDFファイルが保存されます。
if __name__ == "__main__":
#カレントディレクトリを取得
current_dir = os.getcwd()
#入力ディレクトリを取得
indir = current_dir + "\\input\\"
indir_error = current_dir + "\\input_error\\"
#出力ディレクトリを取得
outdir = current_dir + "\\output\\"
outdir_tmp = current_dir + "\\output_tmp\\"
# 出力用フォルダがない場合は作る
if os.path.isdir(outdir) == False:
os.mkdir(outdir)
if os.path.isdir(outdir_tmp) == False:
os.mkdir(outdir_tmp)
if os.path.isdir(indir_error) == False:
os.mkdir(indir_error)
#入力ディレクトリ内の画像を選択
all_images = glob.glob(indir + "*")
#それぞれの画像に対する処理
for img in all_images:
#入力画像の画像名を取得(拡張子付き)
basename = os.path.basename(img)
print(basename)
#入力画像の画像名から拡張子を分離
name,ext = os.path.splitext(basename)
try:
#images = convert_from_path(img)
with open(img,"rb") as pdf_file: #imgとあるが入力となるPDFファイルのこと。
source = PdfFileReader(pdf_file)
num_pages = source.getNumPages()
#シングルページPDFはoutput_tmpにコピーして次の画像に進む
if num_pages == 1:
copyfile(img,outdir_tmp + basename )
continue
for i in range(0,num_pages):
file_object = source.getPage(i)
pdf_file_name = outdir_tmp + name + "_" + str(i+1) + ".pdf"
pdf_file_writer = PdfFileWriter()
with open(pdf_file_name, 'wb') as f:
pdf_file_writer.addPage(file_object)
pdf_file_writer.write(f)
except:
print(basename + "*** error ***")
copyfile(img,indir_error + basename )
やりたいこと②:PDFをJPEG画像に変換
こちらはGhostScriptで実行しています。
やりたいこと①でページ分割したPDFファイルを順に選択していき、JPEGへと変換しています。
最初にコマンドを定義しましてsubprocessモジュールで実行するというような流れです。
print("***** pdf to jpg *****")
######################################
#
# pdf2jpeg(ghost script)関連の設定
#
######################################
exe_name = r'C:\Program Files\gs\gs9.50\bin\gswin64c.exe'
exe_option = "-dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -dJPEGQ=100 -dQFactor=1.0 -dDisplayFormat=16 -r600"
exe_outfile = "-sOutputFile="
#入力ディレクトリ内の画像を選択
all_pdfs = glob.glob(outdir_tmp + "*")
for pdf in all_pdfs:
#入力画像の画像名を取得(拡張子付き)
basename = os.path.basename(pdf)
print(basename)
#入力画像の画像名から拡張子を分離
name,ext = os.path.splitext(basename)
outputfile = outdir + name + ".jpg"
cmd_list = list()
cmd_list.append(exe_name)
cmd_list.extend(exe_option.split()) # ここはappendではなくextendで
cmd_list.append(exe_outfile + outputfile)
cmd_list.append(pdf)
subprocess.call(cmd_list)
全体
import os
import glob
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
import subprocess
from shutil import copyfile
"""
メイン
"""
if __name__ == "__main__":
#カレントディレクトリを取得
current_dir = os.getcwd()
#入力ディレクトリを取得
indir = current_dir + "\\input\\"
indir_error = current_dir + "\\input_error\\"
#出力ディレクトリを取得
outdir = current_dir + "\\output\\"
outdir_tmp = current_dir + "\\output_tmp\\"
# 出力用フォルダがない場合は作る
if os.path.isdir(outdir) == False:
os.mkdir(outdir)
if os.path.isdir(outdir_tmp) == False:
os.mkdir(outdir_tmp)
if os.path.isdir(indir_error) == False:
os.mkdir(indir_error)
#入力ディレクトリ内の画像を選択
all_images = glob.glob(indir + "*")
#それぞれの画像に対する処理
for img in all_images:
#入力画像の画像名を取得(拡張子付き)
basename = os.path.basename(img)
print(basename)
#入力画像の画像名から拡張子を分離
name,ext = os.path.splitext(basename)
try:
#images = convert_from_path(img)
with open(img,"rb") as pdf_file: #imgとあるが入力となるPDFファイルのこと。
source = PdfFileReader(pdf_file)
num_pages = source.getNumPages()
#シングルページPDFはoutput_tmpにコピーして次の画像に進む
if num_pages == 1:
copyfile(img,outdir_tmp + basename )
continue
for i in range(0,num_pages):
file_object = source.getPage(i)
pdf_file_name = outdir_tmp + name + "_" + str(i+1) + ".pdf"
pdf_file_writer = PdfFileWriter()
with open(pdf_file_name, 'wb') as f:
pdf_file_writer.addPage(file_object)
pdf_file_writer.write(f)
except:
print(basename + "*** error ***")
copyfile(img,indir_error + basename )
print("***** pdf to jpg *****")
######################################
#
# pdf2jpeg(ghost script)関連の設定
#
######################################
exe_name = r'C:\Program Files\gs\gs9.50\bin\gswin64c.exe'
exe_option = "-dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -dJPEGQ=100 -dQFactor=1.0 -dDisplayFormat=16 -r600"
exe_outfile = "-sOutputFile="
#入力ディレクトリ内の画像を選択
all_pdfs = glob.glob(outdir_tmp + "*")
for pdf in all_pdfs:
#入力画像の画像名を取得(拡張子付き)
basename = os.path.basename(pdf)
print(basename)
#入力画像の画像名から拡張子を分離
name,ext = os.path.splitext(basename)
outputfile = outdir + name + ".jpg"
cmd_list = list()
cmd_list.append(exe_name)
cmd_list.extend(exe_option.split())
cmd_list.append(exe_outfile + outputfile)
cmd_list.append(pdf)
subprocess.call(cmd_list)
さいごに
やりたいことに対してサクッと作ってしまったソースコードのため、かなり汚いソースコードとなってしまいました笑
(笑い事ではないですが)
また、GhostScriptでも上手くJPEG変換が出来ないPDFもありました。
原因ははっきりしていないのですが、少し調べたところフォントが対応していないような感じでした。
反響次第ではもう少し調べてみようと思います。
何かありましたらコメントをお願い致します。