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

#はじめに
こんにちは！
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405687/8a336df8-11e0-2480-7f9b-ed955a9c176c.png)


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

<details><summary>セットアップ画面</summary><div>

![ghostscript_setup_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405687/17a13fec-4b55-1f95-4a69-657359c6c049.png)
![ghostscript_setup_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405687/617028ed-42bd-f7d3-92da-3882a95274f1.png)
![ghostscript_setup_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405687/440ff2b8-f085-c417-ea66-c0350e9893c7.png)
![ghostscript_setup_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405687/793bde19-d01e-cb21-3d99-d5a82d74cf14.png)
</div></details>



※ghostscriptはPyPIでもpipコマンドでインストール出来るようですが、本稿執筆にあたって、こちらは特に確認していません。
https://pypi.org/project/ghostscript/


#やりたいこと①：PDFをページ分割
「はじめに」で説明したように複数ページあるPDFに必要な処理であり、元々1ページのPDFであれば必要ありません。
長くなるので、分割に関係あるところだけをピックアップしました。
お時間のない方は全体ソースコードもこの後の章に載せているので、そちらをご確認ください。

前提としてソースコードと同じディレクトリに「input」フォルダを作成して、そこに入力画像となるPDFファイルを置いてください。
「output_tmp」というディレクトリが自動的に作られ、ページ分割されたPDFファイルが保存されます。

```Python

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モジュールで実行するというような流れです。


```Python

    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)



```

#全体
```Python

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

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