Python から Win32 API 経由で印刷する

Win32 API から印刷をするためには、プリンタデバイスコンテキスト (Printer DC) を利用します。具体的には以下のような順序で印刷します。

  1. プリンタドライバからハンドルを取得する
  2. プリンタドライバのステータス API から印刷可能か同かを取得する
  3. プリンタデバイスコンテキストを作成する
  4. ドキュメントを開始する
  5. 必要であればフォント等を設定し、印字、改ページ処理などをする
  6. ドキュメントを終了する (この時点でプリンタスプールサービスに登録されるようです)
  7. プリンタデバイスコンテキストを開放する
  8. プリンタドライバのステータス API を監視し、印刷が正常に終了したかを取得する
  9. プリンタドライバのハンドルを解放する

太字の手順 (3 - 7) は Win32 API で共通ですが、それ以外の手順 (1, 2, 8, 9) はプリンタドライバに依存しているため、Python から制御したい場合はライブラリを作成する必要があります。これについては、ドライバマニュアルとにらめっこしながら ctypes.windll でがんばります・・・。プリンタ接続、用紙切れ、ミスフィード等のプリントエラーを制御する必要がなければ、書く必要はありません (排他制御が必要なプリンタを除く)。プリンタドライバ毎に変わる部分は置いといて、太字の Win32 API の部分の覚書です。

プリンタデバイスコンテキストを作成する

import win32ui
import win32con

PRINTER_NAME = '[コンパネ -> プリンタとFAX -> に登録しているプリンター名]'
PIXELS_PER_INCH = 1440 # 1 インチ毎のピクセル数
INCH_PER_POINT = 72 # 1 インチ毎のポイント数
SCALE_FACTOR = int(PIXELS_PER_INCH / INCH_PER_POINT) # わざわざ計算せず 20 と指定する場合が多い

dc = win32ui.CreateDC()
dc.CreatePrinterDC(PRINTER_NAME) # 指定したプリンタ名のプリンタデバイスコンテキストを作成する
self.dc.SetMapMode(win32con.MM_TWIPS) # デバイスコンテキストのマッピングモード (座標単位) を設定する

SetMapModewin32con.MM_TWIPS を指定しているため、1 インチ毎のポイント数 20 を計算しています。その他の単位で印字したい場合は、msdn のサイトで詳しく解説されています。

ドキュメントを開始する

dc.StartDoc(u'[ドキュメント名]') # 印刷ジョブを区別するためにユニークなドキュメント名を設定する

必要であればフォント等を設定し、印字、改ページ処理などをする

u"""
フォントは以下が指定可能::
    name -- フォント名
    width -- 平均文字幅
    height -- フォントの高さ
    weight -- フォントの太さ
        0 (win32con.FW_DONTCARE) - 1000 (win32con.FW_BLACK) までで指定する。
        標準は 400 (win32con.FW_REGULAR)。
    italic -- 斜体にするかどうか
    underline -- 下線を付けるかどうか
    pitch and family -- ピッチとファミリ
    charset -- 文字セット
        標準は Windows 文字セット (win32con.ANSI_CHARSET)
        日本語の場合はシフト JIS 文字セット (win32con.SHIFTJIS_CHARSET)
詳細: http://msdn.microsoft.com/ja-jp/library/cc428368.aspx
"""
fontdict = {
    "height": SCALE_FACTOR * 10, # 10 ポイント
    "name": u"[フォント名]", # "MS ゴシック" 等のフォント名
    "charset": win32con.SHIFTJIS_CHARSET, # シフト JIS 文字セット
}
font = win32ui.CreateFont(fontdict) # CFont インスタンスを作成

# フォントオブジェクトのセット: http://msdn.microsoft.com/ja-jp/library/cc410576.aspx
# フォントをセットすると今までセットされてたフォントを返してくれるので保持しとく。
oldfont = dc.SelectObject(font) 

# 描画: http://msdn.microsoft.com/ja-jp/library/cc428775.aspx
dc.TextOut(0, SCALE_FACTOR * 10 * -1, u"印字") # 1 行目
dc.TextOut(0, SCALE_FACTOR * 10 * -2, u"印字") # 2 行目
dc.TextOut(0, SCALE_FACTOR * 10 * -3, u"印字") # 3 行目

# フォントを元に戻す
dc.SelectObject(oldfont)

# 改ページ処理
dc.EndPage() 

改行処理は手動でする必要があります。私は 1 文字ずつ印字していき、指定した横幅に達したら改行するように制御しています。

# 行の幅と高さを計算: http://msdn.microsoft.com/ja-jp/library/z7e878zz%28VS.80%29.aspx
x, y = dc.GetTextExtent(u"長文 ...")

アライン設定は SetTextAlign を使います。

# テキスト配置フラグ設定: http://msdn.microsoft.com/ja-jp/library/cc428723.aspx
dc.SetTextAlign(win32con.TA_LEFT | win32con.TA_TOP | win32con.TA_NOUPDATECP) # 左寄せ
dc.SetTextAlign(win32con.TA_CENTER | win32con.TA_TOP | win32con.TA_NOUPDATECP) # センタリング
dc.SetTextAlign(win32con.TA_RIGHT | win32con.TA_TOP | win32con.TA_NOUPDATECP) # 右寄せ

ドキュメントを終了する

dc.EndDoc()

プリンタデバイスコンテキストを開放する

dc.DeleteDC()

コメント

このブログの人気の投稿

Disqus のスケール - Django 編

Disqus のスケール - Django で月間80億PVを処理する