5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pythonでGhostScriptを動かし、PDFをページ分割して、JPEG画像に変換してみた

Last updated at Posted at 2020-01-13

#はじめに
こんにちは!
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_download.png

ダウンロードしたファイルを実行してセットアップを行ってください。

セットアップ画面

ghostscript_setup_1.png
ghostscript_setup_2.png
ghostscript_setup_3.png
ghostscript_setup_4.png

※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もありました。
原因ははっきりしていないのですが、少し調べたところフォントが対応していないような感じでした。
反響次第ではもう少し調べてみようと思います。

何かありましたらコメントをお願い致します。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?