PillowとPyPDFで文字化けしたスキャン画像をPDF化

# はじめに
スキャンした画像データをとりあえずzipで固めておいて、家に持ち帰って展開したらなぜか文字化け…
なんて経験ありませんか？　**僕はあります！（半ギレ）**
ただ、案外連番だけは文字化けせず残っているのでファイルの順番などはなんとかわかる状態になっていることも多々あります。
(例 æ–‡å—000.jpg , æ–‡ås001.jpg) 
ファイル名からこの文字化け部分だけ排除してきれいな連番ファイルに形成できれば見栄えもいいし、後の作業的にも助かります。
100枚くらいのデータだっただけに手直しするのも億劫なので軽くPythonスクリプトを作ってみることにしました。
ついでに画像データから一つのPDFにするのもワンタッチでできるようにしてみました。

その際、画像処理に**Pillow**を PDF化に**PyPDF2**を利用したのでその辺を解説していきたいと思います。

スクリプトは[github](https://github.com/tubone24/fileName2SerialNumber)にあげています。
スクリプトの使用方法などはREADMEをご参照下さい

## 関数の紹介
急いで書いたのでぐだぐだなスクリプトですが以下の関数で構成されています

* name2number(folderpass, digits, extension)
* changeNameHand(existfiles)
* addstr(before, after, digits, extension)
* image2pdf(filename, digits, extension, removeflug)
* makeZip(filename, flug)
* main()

以下軽く紹介します。冗長な内容なので読み飛ばしてください
### name2number(folderpass, digits, extension)
引数として受け取った画像データのあるフォルダパスの画像たち（拡張子で指定したもののみ）から
文字化けしていない部分（æ–‡å—000.jpg でいうところの000）からファイル名を連番にします。
ファイル名の書き換えにはos、正規表現の扱いについてはreモジュールを使用しています。
戻り値は処理をスキップしたファイル名の配列です。

### changeNameHand(existfiles)
name2numberの戻り値は連番が被ってしまいファイル名の書き換えをスキップしたファイル名を入れた配列です。
この関数はそれを引数として受け取ると標準入出力にてインタラクティブにファイル名を聞いて、書き換える作業をします。
ファイル名の書き換えにはos、正規表現の扱いについてはreモジュールを使用しています。
また、画像確認のための画像表示にはPillow(PIL)モジュールを使用しています。

### addstr(before, after, digits, extension)
引数beforeの文字列を連番の前に、引数afterの文字列を連番の後ろにくっつける関数です。連番だけでは味気ないという場合使います
ファイル名の書き換えにはos、正規表現の扱いについてはreモジュールを使用しています。

### image2pdf(filename, digits, extension, removeflug)
PillowとPyPDF2を利用して、カレントディレクトリの画像データたちを一つのPDFにします。
後述で詳しく解説します

### makeZip(filename, flug)
カレントディレクトリのデータをzipで固めます。
Zipfileモジュールを使用しています。

### main()
コマンドライン引数を取得するための関数です。
コマンドライン引数取得のためにargparseモジュールを利用しています。


# PillowとPyPDFで画像をPDF化
## image2pdf()のスクリプト抜粋

```py3:fileName2SerialNumber.py
def image2pdf(filename, digits, extension, removeflug):
    u"""
    画像ファイルをPDF化する関数
    """
    if (extension != ".jpg" and ".png" and ".gif"): # 画像じゃない場合弾く
        print("対応外の画像ファイル！ jpg, png, gifでオナシャス")
        sys.exit(1)
    
    fileWriter = PdfFileWriter()
    files = os.listdir()
    ext = re.compile(extension)
    files.sort()
    count = 1
    removefiles = []
    for file in files:
        num = re.search('\\d{' + str(digits) +'}', file)
        if (num == None):
            pass
        else:
            if (ext.search(file) and num):
                image = PIL.Image.open(file)
                pdfFile = str(file).replace(extension, ".pdf")
                image.save(pdfFile, "PDF", resolution = 100.0)
                with open(pdfFile, "rb") as f:
                    fileReader = PdfFileReader(f, "rb")
                    pageNum = fileReader.getNumPages()
                    for i in range(pageNum):
                        fileWriter.addPage(fileReader.getPage(i))
                        print("%s を%d ページ目に書き込みます" % (str(file), count))
                        count += 1
                    removefiles.append(pdfFile)
                    if (removeflug):
                        removefiles.append(file)
                    with open(filename, "wb") as outputs:
                        fileWriter.write(outputs)
    print("-------------------------------------------------------")
    print("書き込み終了！ ファイル名 %s \n" % filename)
    
    for file in removefiles:
        os.remove(file)
        print("ファイル名　%sを削除しました" % str(file))
    
    print("--------------------------------------------------------")
    print("終わり！成果物: %s" % filename)
    return None
```

## Pillow(PIL)の作業
PillowはPythonで画像処理をするためのモジュールです。
PIPとかで入ります。

ファイルを画像で開くには

```py3:
image = PIL.Image.open(file)
```

とします。

今回は画像をPDFとして保存したいのでPDFに書き換える作業を入れます。そこで


```py3:
image.save(image, "PDF", resolution = 100.0)
```

とすることでPDF形式で画像を保存できます。 "PDF"の部分を別の画像規格にしたり、resolutionを100以外にすることで画像の品質を自由に変更することも可能です。
PDF形式に直すときのポイントとしてimageファイルを読み込む前にimageファイルの拡張子を.pdfに書き換えてあげる必要があるようです。そこで本スクリプトでは

```py3:
pdfFile = str(file).replace(extension, ".pdf")
```

として拡張子を変えています。

また、この関数では使用していませんが画像を表示するには
PIL.image.open()で画像を開いた後

```py3:
image.show()
```

で表示することができます。


## PyPDF2での作業
PyPDF2は複数のPDFファイルを一つにまとめたり、PDFからテキストデータを吸い取ったりできる便利なモジュールです。
PIPが使えます。

まずファイルを書き出すためのインスタンスを作成します。

```py3:
fileWriter = PdfFileWriter()
```

また、PDFファイルを読み込むためのインスタンスは

```py3:
fileReader = PdfFileReader(open(pdffile, "rb"), "rb")
```

で作成します。ファイルのopenが絡むのでwithを使って

```py3:
with open(pdfFile, "rb") as f:
    fileReader = PdfFileReader(f, "rb")
```

とした方が面倒がないと思います。

現在の総ページ数を確認するには

```py3:
pageNum = fileReader.getNumPages()
```

でpageNumにページ数が入ります。

PDFのページを追加するには

```py3:
fileWriter.addPage(fileReader.getPage(pageNumber))
```

とします。getpage(ページ数)で指定されたページ番号のページオブジェクトを返します。
ページオブジェクトを引数としてaddPageすることで指定番目にページが追加されます。

編集が完了したらいよいよPDFファイルとして書き出します。

書き出しには

```py3:
fileWriter.write(open(filename, "wb")
```

で書き込めます。open関数を使うのでwith文を使って


```py3:
with open(filename, "wb") as outputs:
     fileWriter.write(outputs)
```

とした方が面倒がないと思います。

# おわりに
PillowとPyPDF2を使って業務効率アップだ！