wx.Image はプラットフォーム非依存 (platform-independent) のイメージオブジェクトです。
画像ファイルの読み込み、保存などの機能を持っており、ピクセルデータとしてメモリ上に展開します。
どの形式の画像ファイルを読み込んでも、wx.Image オブジェクトとしてロードした時点で、抽象化された単純なピクセルデータとして扱えるようになります。
イメージオブジェクトに対して複雑な描画(線や円の描画)を行う場合は、通常は wx.Bitmap オブジェクトに変換してからデバイスコンテキスト (wx.DC) 経由で描画を行います。wx.Bitmap はプラットフォーム依存 (platform-dependent) のイメージオブジェクトです。
イメージをディスプレイ上に描画したり、イメージ自体を編集したりするときに使用します。
これらの操作は、描画用の API をまとめたデバイスコンテキスト (wx.DC) 経由で行います。画像ファイルから wx.Image オブジェクトを作成するには、wx.Image のコンストラクタを使用します。
wx.Image(String name, long type=BITMAP_TYPE_ANY, int index=-1) -> Image
name パラメータでは、ロードする画像ファイルのパスを指定します。
type パラメータでは、画像ファイルを展開してピクセルデータに変換するためのイメージハンドラ (wx.ImageHandler) のタイプを指定します。
例えば、wx.BITMAP_TYPE_PNG を指定すると、wx.PNGHandler という PNG ファイルを展開するためのイメージハンドラが使用されます。
デフォルトの BITMAP_TYPE_ANY のままにしておけば、ファイルの内容に応じて適切なイメージハンドラを用いてロードしてくれるので、ほとんどの場合、このパラメータを指定する必要はありません。
index パラメータは、GIF や ICO、TIFF ファイルのように、ひとつの画像ファイルに複数のイメージを含んでいる場合に、どのイメージをロードするかを指定します(0-base 指定)。
image = wx.Image('sample.png')
wx.Image のコンストラクタとして、画像の MIME タイプ(image/jpeg など)をテキストで指定してロードするものも用意されています。
wx.ImageFromMime(String name, String mimetype, int index=-1) -> Image
wx.EmptyImage(int width=0, int height=0, bool clear=True) -> Image
指定したサイズの空のイメージを作成します。全てのピクセルは黒で初期化されます。
wx.ImageFromData(int width, int height, buffer data) -> Image
R,G,B の順で並んだ RGB データを元に wx.Image オブジェクトを作成します。
データのサイズは width x height x 3 である必要があります。
wx.Bitmap から wx.Image を作成するには、wx.Image のコンストラクタの wx.ImageFromBitmap を使用するか、wx.Bitmap のメソッド ConvertToImage() を使用します。
wx.ImageFromBitmap(Bitmap bitmap) -> Image
wx.Bitmap#ConvertToImage() -> Image
wx.Bitmap(String name, int type=BITMAP_TYPE_ANY) -> Bitmap
パラメータは、wx.Image のコンストラクタと同様です。
内部で wx.Image を作成し、wx.Bitmap インスタンスが生成されます。
wx.EmptyBitmap(int width, int height, int depth=-1) -> Bitmap
指定したサイズの空の wx.Bitmap オブジェクトを作成します。
depth パラメータでは、color depth(色のビット数)を指定することができます。
デフォルトの -1 を指定すると、現在のディスプレイの color depth が使用されます。
1 を指定すると、モノクロ画像になります。
wx.Image から wx.Bitmap を作成するには、wx.Bitmap のコンストラクタの wx.BitmapFromImage を使用するか、wx.Image のメソッド ConvertToBitmap() を使用します。
wx.BitmapFromImage(Image image, int depth=-1) -> Bitmap
wx.Image#ConvertToBitmap(int depth=-1) -> Bitmap
wx.Iamge#GetWidth() -> int
wx.Image#GetHeight() -> int
wx.Iamge#GetSize() -> Size
wx.Image#GetRed(int x, int y) -> byte
wx.Image#GetGreen(int x, int y) -> byte
wx.Image#GetBlue(int x, int y) -> byte
これらのメソッドは 0 ~ 255 の範囲で Red, Green, Blue の値を取得します。
wx.Image#SetRGB(int x, int y, byte r, byte g, byte b)
r, g, b パラメータには 0 ~ 255 の範囲で Red, Green, Blue の値を取得します。
多くのピクセル値を操作する場合、すべてのピクセルに対して wx.Image#GetRed() や、SetRGB() メソッドを呼び出すと処理に時間がかかります。
そのような場合は、GetData() メソッドですべてのピクセルデータを取得し、そのデータを編集後に SetData() メソッドで書き戻します。
wx.Image#GetData() -> PyObject
wx.Image#SetData(buffer data)
SetData() メソッドでは、wx.ImageFromData() と同様に、R,G,B の順で並んだ RGB データをセットします。
データのサイズは width x height x 3 である必要があります。
wxPython では、色々な形式のイメージや、デバイスに対して共通の API で描画処理を行えるようにするために、デバイス・コンテキストのコンセプトが用いられています (wx.DC)。
実際に描画処理を行う場合は、以下のような wx.DC のサブクラスを用途によって使い分けます。
wx.DC インスタンスは、ローカル変数として使用することを前提に設計されているため、グローバル変数やメンバ変数として保持してはいけません。
wx.ClientDC(widget のクライアント領域への描画用)wx.WindowDC(widget の全体領域への描画用)wx.ScreenDC(デスクトップ全体への描画用)wx.PaintDC(EVT_PAINT イベント内での描画用(クライアント領域への描画))wx.MemoryDC(Bitmap オブジェクトへの描画用)wx.MetaFileDC(Windows metafile 作成用)wx.PostscriptDC(Encapsulated PostScript file (.eps) 作成用)wx.PrinterDC(プリンタ出力用 (for Windows))wx.BufferedDC(複数の描画処理をまとめて実行するアダプタ)wx.BufferedPaintDC(複数の描画処理をまとめて実行するアダプタ(wx.PaintDC 用))wx.ClientDC は、ウィジェット (wx.Window) のクライアント領域へ描画を行うためのデバイス・コンテキストです。
コンストラクタで、描画先の wx.Window オブジェクトを指定します。
wx.ClientDC(Window win) -> ClientDC
wx.Frame オブジェクトを指定した場合、タイトルバー、ツールバー、ボーダーなどはクライアント領域に含まれません。
wx.WindowDC は wx.ClientDC に似ていますが、対象となるウィジェット (wx.Window) の領域全体に描画を行うことができるデバイス・コンテキストです。
そのため、wx.Frame オブジェクトを指定した場合は、タイトルバー、ツールバー、ボーダー領域など wx.Frame の領域すべてが描画対象となります。
wx.WindowDC(Window win) -> WindowDC
ディスプレイ全体(デスクトップ)に対して描画処理を行いたい場合は、デバイス・コンテキストとして wx.ScreenDC を使用します。
wx.ScreenDC() -> ScreenDC
クライアント領域の再描画タイミングで発生する ‘‘EVT_PAINT’’ イベントのハンドラの中では、wx.ClientDC の代わりに、wx.PaintDC インスタンスを生成する必要があります。
ここで wx.PaintDC を使用しなければいけないのは、wx.PaintDC が EVT_PAINT イベント発生時に、再描画領域を考慮した最適な描画処理を行うようになっているからです。
wx.PaintDC(Window win) -> PaintDC
wx.MemoryDC はメモリ上に確保した wx.Bitmap オブジェクトに対して描画を行うためのデバイス・コンテキストです。
wx.MemoryDC(Bitmap bitmap=NullBitmap) -> MemoryDC
wx.MemoryDC を用いて描画を行う前に、必ず描画先の wx.Bitmap オブジェクトをセットしておく必要があります。
wx.Bitmap オブジェクトは、コンストラクタか、SetObject() メソッドでセットできます。
wx.MemoryDC#SelectObject(Bitmap bitmap)
編集された wx.Bitmap オブジェクトは、wx.DC#DrawBitmap() メソッドで別のデバイス・コンテキストへ描画したり、wx.Bitmap#SaveFile() メソッドで画像ファイルとして保存したりすることができます。
wx.MetaFileDC は、Microsoft Windows の MetaFile を作成するためのデバイス・コンテキストです。
wx.MetaFileDC(String filename=EmptyString, int width=0, int height=0,
String description=EmptyString) -> MetaFileDC
描画後に Close() メソッドを呼び出すと、描画結果の wx.Metafile オブジェクトを取得することができ、その SetClipboard() メソッドを使って描画内容をクリップボードにコピーする、といったことができます。
wx.MetaFileDC#Close(self) -> MetaFile
wx.MetaFile#SetClipboard(int width=0, int height=0) -> bool
wx.PostScriptDC は、Encapsulated PostScript ファイル (.eps) を作成するためのデバイス・コンテキストです。
wx.PostScriptDC(wx.PrintData printData) -> PostScriptDC
wx.PrinterDC を使用すると、Windows のプリンタ・ドライバに対して描画処理を行うことができます。
wx.PrinterDC(wx.PrintData printData) -> PrinterDC
wx.BufferedDC は、あるデバイス・コンテキストへの描画処理をバッファリングし、一度に描画内容を反映するようにします。
例えば、wx.ClientDC への連続した描画を wx.BufferedDC でバッファリングすれば、画面上での描画のちらつきを防ぐことができます。
wx.BufferedDC(DC dc, Bitmap buffer=NullBitmap, int style=BUFFER_CLIENT_AREA) -> BufferedDC
wx.BufferedDC(DC dc, Size area, int style=BUFFER_CLIENT_AREA) -> BufferedDC
EVT_PAINT イベントのハンドラの中で描画処理をバッファリングしたい場合は、wx.BufferedDC の代わりに wx.BufferedPaintDC を使用します。
wx.BufferedPaintDC(Window window, Bitmap buffer=NullBitmap, int style=BUFFER_CLIENT_AREA) -> BufferedPaintDC
wx.BufferedDC、wx.BufferedPaintDC は内部に描画内容のバッファリングのために Bitmap オブジェクトを保持しており、デバイス・コンテキストがスコープを外れるとき(ガーベジ・コレクトされるとき)に自動的に内部の Bitmap の内容を Blit() して実際の描画内容を反映するようになっています。

以下のコードは、描画用バッファとして空の wx.Bitmap を作成し、適切なタイミングで(EVT_PAINT イベント発生時に)その描画内容を画面に反映させるサンプルです。
このような構成にすることで、ウィンドウの一部が他のウィンドウで隠れて再び表示された時に、必要な部分だけを再描画してくれます。
さらに、多くの描画処理を行った場合のちらつきもなくなります。
ウィンドウのサイズが変化した場合は、内部の描画用バッファ (wx.Bitmap) を新しいサイズで作成し直しています。
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Title", size=(250,200))
self.InitBuffer()
# Bind events to redraw.
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self, self.buffer)
def OnSize(self, evt):
self.InitBuffer()
def InitBuffer(self):
w, h = self.GetClientSize()
self.buffer = wx.EmptyBitmap(w, h)
self.DrawToBuffer()
def DrawToBuffer(self):
# Create buffered device context.
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
# Clear the buffer.
dc.SetBackground(wx.Brush('white'))
dc.Clear()
# Draw graphics.
dc.DrawText('Hoge hoge', 10, 10)
dc.DrawLine(10, 10, 200, 10)
dw, dh = dc.GetSize()
dc.SetPen(wx.Pen('blue', 3))
dc.DrawCircle(dw/2, dh/2, 50)
if __name__ == '__main__':
app = wx.PySimpleApp()
MyFrame().Show()
app.MainLoop()
以下のコードは、上記のコードの描画用バッファを確保する部分を汎用的な PaintBuffer クラスとしてライブラリ化したものです。
PaintBuffer クラスは、任意の wx.Window オブジェクト用の描画用バッファを作成します。
import wx
class PaintBuffer:
def __init__(self, window, paintHandler=None):
self.window = window
self.paintHandler = paintHandler
# Create drawing buffer.
self.InitBuffer()
# Bind events to redraw.
self.window.Bind(wx.EVT_PAINT, self.OnPaint)
self.window.Bind(wx.EVT_SIZE, self.OnSize)
def SetPaintHandler(handler):
self.paintHandler = handler
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self.window, self.buffer)
def OnSize(self, evt):
self.InitBuffer()
def InitBuffer(self):
w, h = self.window.GetClientSize()
self.buffer = wx.EmptyBitmap(w, h)
self.DrawToBuffer()
def DrawToBuffer(self):
if self.paintHandler:
dc = wx.BufferedDC(wx.ClientDC(self.window), self.buffer)
self.paintHandler(dc)
import wx
import paintBuffer
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Title", size=(250,200))
self.buffer = paintBuffer.PaintBuffer(self, self.PaintHandler)
def PaintHandler(self, dc):
# Clear the buffer.
dc.SetBackground(wx.Brush('white'))
dc.Clear()
# Draw graphics.
dw, dh = dc.GetSize()
dc.SetPen(wx.Pen('blue', 3))
dc.DrawCircle(dw/2, dh/2, 50)
if __name__ == '__main__':
app = wx.PySimpleApp()
MyFrame().Show()
app.MainLoop()
import wx
if __name__ == '__main__':
app = wx.PySimpleApp()
data = wx.PrintData()
data.SetFilename('test.eps')
data.SetPaperId(wx.PAPER_LETTER)
dc = wx.PostScriptDC(data)
dc.StartDoc('')
dc.DrawCircle(300, 300, 100)
dc.EndDoc()

wx.Bitmap をデバイス・コンテキストで描画するには、wx.DC の以下のメソッドを使用します(wx.Icon も同様のメソッドで描画できます)。
DrawBitmap(Bitmap bmp, int x, int y, bool useMask=False)
DrawIcon(Icon icon, int x, int y)
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Title", size=(150,100))
# Load bitmap.
self.bitmap = wx.Bitmap('sample.png')
# Bind events.
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
# Clear the buffer.
dc.SetBackground(wx.Brush('sky blue'))
dc.Clear()
# Draw graphics.
dc.DrawBitmap(self.bitmap, 10, 10)
if __name__ == '__main__':
app = wx.PySimpleApp()
MyFrame().Show()
app.MainLoop()