WindowsのPythonでPDFの印刷をする:外部アプリケーションを使う


※タイトルに書いておきながらタイトルにも書いてありますが、Pythonはいうほど関係ありません。

Windows上でPythonを使ってPDFを印刷させる方法を探してみました。

今回は、外部のアプリケーションを呼び印刷させます。

> 追記:2015-07-03:
> サンプルのコードは、`python [filename]` で出来るようになってます。一部違いますし、例外等何も入れてません。詳しくはコードを確認下さい。

# Adobe Reader, Adobe Acrobatのコマンドラインを利用する

[Acrobat および Adobe Reader のコマンドラインオプション](https://helpx.adobe.com/jp/acrobat/kb/510705.html)

Adobe ReaderやAdobe Acrobatは、コマンドラインオプションがあります。別のプロセス（インスタンス）で起動したり、印刷をそのまま実行させたり出来ます。

ここでの例では、Adobe Acrobatを利用しています。(`Acrobat.exe`) Adobe Readerは `AcroRd32.exe` を利用します。インストール時のパスもバージョンによって異なります。デメリットはその判定が面倒なところかな？

参考: [Print PDFs with Python? | GeoNet](https://geonet.esri.com/thread/59446)

## Adobe Readerの印刷ダイアログを表示させてから印刷させる

https://gist.github.com/hrsano645/ddd5c111204338576404

```python
# coding: utf-8
from __future__ import division, print_function, absolute_import, unicode_literals

import subprocess
import sys

# ref: https://geonet.esri.com/thread/59446
# ref: https://helpx.adobe.com/jp/acrobat/kb/510705.html

def main(pdffile):
    # acroread = r'C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe'
    acrobat = r'C:\Program Files (x86)\Adobe\Acrobat 11.0\Acrobat\Acrobat.exe'
    
    # '"%s"'is to wrap double quotes around paths
    # as subprocess will use list2cmdline internally if we pass it a list
    # which escapes double quotes and Adobe Reader doesn't like that
    
    cmd = '"{}" /P "{}"'.format(acrobat, pdffile)
    
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = proc.communicate()
    exit_code = proc.wait()


if __name__ == '__main__':
    pdffile = sys.argv[1]
    main(pdffile)
```

## Adobe Acrobatの印刷ダイアログを表示させないで印刷させる（サイレントモード）

この方法では、プリンタ名が必要です。（ない場合のチェックはしていません。どなたかコメント下さい）

https://gist.github.com/hrsano645/a16c3f35deac04b2b4d9

```python
# coding: utf-8
from __future__ import division, print_function, absolute_import, unicode_literals

import subprocess
import sys

# ref: https://geonet.esri.com/thread/59446
# ref: https://helpx.adobe.com/jp/acrobat/kb/510705.html


def main(pdffile, printer_name):
    # acroread = r'C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe'
    acrobat = r'C:\Program Files (x86)\Adobe\Acrobat 11.0\Acrobat\Acrobat.exe'

    # '"%s"'is to wrap double quotes around paths
    # as subprocess will use list2cmdline internally if we pass it a list
    # which escapes double quotes and Adobe Reader doesn't like that

    cmd = '"{}" /N /T "{}" "{}"'.format(acrobat, pdffile, printer_name)

    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = proc.communicate()
    exit_code = proc.wait()


if __name__ == '__main__':
    pdffile = sys.argv[1]
    printer_name = sys.argv[2]
    main(pdffile, printer_name)
```

# Pywin32:Win32API.ShellExecuteを利用する
Pywin32で利用できるWindows APIにある、ShellExecuteを利用します。  

[ShellExecute 関数](https://msdn.microsoft.com/ja-jp/library/cc422072.aspx)


ShellExecuteを使うと、関連付けられたアプリケーションで開くopen, 印刷をするprintが使えます。

このスクリプトで動作すると思われますが、自分の環境では印刷できる時と出来ない時がありました。

参考:
- [Tim Golden's Python Stuff: Print](http://timgolden.me.uk/python/win32_how_do_i/print.html)
- [win32api.ShellExecute](http://docs.activestate.com/activepython/2.7/pywin32/win32api__ShellExecute_meth.html)

https://gist.github.com/hrsano645/b69b071de4b8cb59cbe9

```python
# coding: utf-8
from __future__ import division, print_function, absolute_import, unicode_literals
 
# ref: http://timgolden.me.uk/python/win32_how_do_i/print.html
# ref: http://docs.activestate.com/activepython/2.7/pywin32/win32api__ShellExecute_meth.html
 
import win32api
import sys
 
 
if __name__ == '__main__':
    pdf_file_name = sys.argv[1]
    win32api.ShellExecute(0, "print", pdf_file_name, None, ".", 0)
```

# GSPrintを利用する
Ghostscriptを利用するGSPrint(GSViewに付属)というコマンドラインアプリケーションを利用して印刷します。

まずは、GhostscriptとGSViewをインストールします。（検証時に利用したものは、本家のバージョンですが日本語版も多分同じかと思います）

[Ghostscript 9.16 and GSview 5.0 J (Official Site)](http://www.khotta.org/ghost/#disk)

後は、subprocessモジュールを使ってコマンドを実行します。

-queryオプションを指定しない場合はそのまま印刷されます。

https://gist.github.com/hrsano645/fe73570d0d5d8df4863a

```python
# coding: utf-8
from __future__ import division, print_function, absolute_import, unicode_literals
 
import subprocess
import sys
 
 
# ref: http://stackoverflow.com/questions/4498099/silent-printing-of-a-pdf-in-python
# ref: http://stackoverflow.com/questions/1462842/print-pdf-document-with-pythons-win32print-module
 
def main(pdffile):
    gsprint = r"C:\Program Files\Ghostgum\gsview\gsprint.exe"
 
    # -quertオプションでプリンタ一覧を呼び出す
    cmd = '"{}" -query "{}"'.format(gsprint, pdffile)
 
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = proc.communicate()
    exit_code = proc.wait()
 
 
if __name__ == '__main__':
    pdffile = sys.argv[1]
    main(pdffile)
```

大事なお知らせとして、印刷時の用紙サイズの設定が操作できないので、-queryで印刷ダイアログを出した上で、プリンタ側で拡大縮小の設定をするしかないらしいです。しかし利用しているPX-1700Fは拡大印刷しても何故かしてくれないです。これはプリンタ側の問題かな。

(あとで試したのですが、プリンタの用紙サイズとファイルの設定された用紙サイズが一致してれば綺麗に印刷してくれました。)

印刷時、色がモノクロだったので、GSPrint側で予め指定しないとダメかも。（詳しく検証してませんがオプションを見る限りだと設定必要かな）

参考: 
- [Ghostscript, Ghostview and GSview](http://pages.cs.wisc.edu/~ghost/index.htm)

# （多分）続きます
この他にも、Pythonで利用できるGUIツールキットを使って行う方法もあるようです。wxpythonとpyqt(pyside)でそれらしいものを見つけましたが、まだ検証していません。検証できたら続きを書こうと思います。

その他にも、良い印刷方法を知っている方、いましたらぜひともコメントに記載していただけると助かります。