##
##  Edit at will, that is, feel free to edit the text as required
##
 . Images and bitmaps in wxPython are normally created by loading files from disk.  Working with the images in memory is also a common task for certain types of application.  This recipe set looks at the in-memory manipulation (and particularly the generation) of images for use in wxPython applications.

Table of Contents: <<TableOfContents>>

== Converting Between PIL image, wx.Bitmap and wx.Image ==
 . The Image classes I find myself working with most frequently are wx.Image, wx.Bitmap, and PIL Image. Here are functions I use to convert between them, in all combinations.  I like to have these broken out as six individual functions with related names because the usage and naming in the wx.Windows API can be confusing.  The API also changes relatively frequently.  I believe that the older text in this section is outdated, but I haven't had time to go through it. -- Robb Shecter

{{{#!python
# Tested with wxPython 2.3.4.2 and PIL 1.1.3.
import wx
import Image             # PIL module. Only if you use the PIL library.

def WxBitmapToPilImage( myBitmap ) :
    return WxImageToPilImage( WxBitmapToWxImage( myBitmap ) )

def WxBitmapToWxImage( myBitmap ) :
    return wx.ImageFromBitmap( myBitmap )

#-----

def PilImageToWxBitmap( myPilImage ) :
    return WxImageToWxBitmap( PilImageToWxImage( myPilImage ) )

def PilImageToWxImage( myPilImage ):
    myWxImage = wx.EmptyImage( myPilImage.size[0], myPilImage.size[1] )
    myWxImage.SetData( myPilImage.convert( 'RGB' ).tostring() )
    return myWxImage

# Or, if you want to copy any alpha channel, too (available since wxPython 2.5)
# The source PIL image doesn't need to have alpha to use this routine.
# But, a PIL image with alpha is necessary to get a wx.Image with alpha.

def PilImageToWxImage( myPilImage, copyAlpha=True ) :

    hasAlpha = myPilImage.mode[ -1 ] == 'A'
    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.

        myWxImage = wx.EmptyImage( *myPilImage.size )
        myPilImageCopyRGBA = myPilImage.copy()
        myPilImageCopyRGB = myPilImageCopyRGBA.convert( 'RGB' )    # RGBA --> RGB
        myPilImageRgbData =myPilImageCopyRGB.tostring()
        myWxImage.SetData( myPilImageRgbData )
        myWxImage.SetAlphaData( myPilImageCopyRGBA.tostring()[3::4] )  # Create layer and insert alpha values.

    else :    # The resulting image will not have alpha.

        myWxImage = wx.EmptyImage( *myPilImage.size )
        myPilImageCopy = myPilImage.copy()
        myPilImageCopyRGB = myPilImageCopy.convert( 'RGB' )    # Discard any alpha from the PIL image.
        myPilImageRgbData =myPilImageCopyRGB.tostring()
        myWxImage.SetData( myPilImageRgbData )

    return myWxImage

#-----

def imageToPil( myWxImage ):
    myPilImage = Image.new( 'RGB', (myWxImage.GetWidth(), myWxImage.GetHeight()) )
    myPilImage.fromstring( myWxImage.GetData() )
    return myPilImage

def WxImageToWxBitmap( myWxImage ) :
    return myWxImage.ConvertToBitmap()
}}}
'''But, wait ...  There's more !'''  There are __two kinds of transparency__ that a wx.Image or wx.Bitmap can have: 1) Every pixel is either completely transparent or completely opaque. This binary transparency is a '''transparency mask'''.  2) Each pixel can have a variable amount of transparency that is from completely transparent (alpha value=0) to completely opaque (value=255). The amount of transparency each pixel has is defined by a value from 0 to 255. This is '''alpha transparency'''. For example, a GIF file may have a transparency mask, or no transparency at all. A PNG file, however, may have a transparency mask, alpha transparency or neither. In comparison, JPG files cannot have any kind of transparency.

=== Reading Image Files ===
Creating a wx.Bitmap from an image file :

{{{
    wxBmap = wx.EmptyBitmap( 1, 1 )     # Create a bitmap container object. The size values are dummies.
    wxBmap.LoadFile( filename, wx.BITMAP_TYPE_ANY )   # Load it with a file image.
}}}
Determine whether a bitmap has a mask or alpha transparency :

{{{
    bmapHasMask  = wxBmap.GetMask()    # "GetMask()", NOT "HasMask()" !
    bmapHasAlpha = wxBmap.HasAlpha()
}}}
Creating a wx.Image from an image file is just like that for a wx.Bitmap :

{{{
    wxImg = wx.EmptyBitmap( 1, 1 )     # Create a bitmap container
    wxImg.LoadFile( filename, wx.BITMAP_TYPE_ANY )
}}}
To determine whether the bitmap has a mask or alpha transparency :

{{{
    imgHasMask  = wxImg.HasMask()    # "HasMask()", NOT "GetMask()" !  Egads ...
    imgHasAlpha = wxImg.HasAlpha()
}}}
Reading an image file into a PIL Image :

{{{
    import Image
    pilImage = Image.open( filename )
}}}
The PIL open() function automatically determines the file's image type. wxPython will not allow you to drop the "wx.BITMAP_TYPE_ANY" parameter even though it's not needed. Remember that PIL image transparency can only be the alpha kind. To check if a PIL image has transparency :

{{{
    pilImageHasAlpha = pilImg.mode[ -1 ] == 'A'
}}}
}When PIL reads in a PNG file with a mask, it automatically converts the mask into binary-valued alpha transparency whose values are either 0 for completely transparent or 255 completely opaque. This is usually not what is wanted.

=== Converting Binary-Valued Alpha Transparency into True (256 values) Alpha Transparency ===
PIL image transparency can only be the true, 256-valued alpha kind, but a wx.Bitmap and a wx.Image can have either kind. To convert a wx.Image transparency mask in to true alpha transparency :

{{{
    imgHasMask  = wxImg.HasMask()
    if wxImg.HasMask() :
        wxImg.InitAlpha()
}}}
To handle all the various image type conversions while also properly copying any transparency the following '''ImgConv.py''' module can be used. Make the calls with any flag parameters at their default values, that is, don't even include them in the call parameter list. If you start with a wx.Bitmap or a wx.Image that has either a transparency mask or alpha transparency, these routines will carry over that transparency to a PIL image with alpha. A transparency mask will always be converted into alpha transparency. PIL images can have only have alpha for transparency, never masks. So, when this package converts a PIL image with transparency, the resulting wx.Image or wx.Bitmap will have alpha transparency, not a mask.

You can use the flag parameters '''addAlphaLayer''' and '''delAlphaLayer''' to optionally :  1) Create an image with a alpha transparency when a source image had none (addAlphaLayer=True), or conversely, 2) Prevent alpha from automatically being created in the new image when the source image does has alpha (delAlphaLayer=True).

[[attachment:ImgConv.py]] [[attachment:Win32IconImagePlugin.py]]

This module contains six conversion functions. By default it automatically preserves any transparency that is present in the input image. This is usually what is wanted when displaying them in an app.

{{{
WxBitmapFromPilImage()
WxImageFromPilImage()

WxBitmapFromWxImage()
PilImageFromWxImage()

WxImageFromWxBitmap()
PilImageFromWxBitmap()
}}}
The '''BitmapManip.py''' module has utility functions for extracting and combining masks useful for advanced image manipulation. Wx.Frames can be created that are free-form non-rectangular with semi-transparent background images overlaid with completely opaque and dynamically changing text.

[[attachment:BitmapManip.py]]

== Conversions Between wx.Image, wx.Bitmap, wx.Cursor, wx.Icon and String Data ==
wx.Image to wx.Bitmap :

{{{
    myWxBmap = myWxImg.ConvertToBitmap()
}}}
or :

{{{
    myWxBmap = wxBitmapFromImage( myWxImg )
}}}
wxImage to String Data :

{{{
    myStrData = myWxImg.GetData()
}}}
This returns a binary data Python string of of length (width * height * 3).

Convert String Data to a wx.Image :

{{{
wxImg = wx.Image()
wxImg.SetData( myStrData )
}}}
Python string of binary data to a wx.Bitmap : Go through wx.Image to get a wx.Bitmap.

DATA to a wx.Icon : Should be possible, but I don't see an overloaded-constructor name for it.

wx.Icon to wxBitmap :

{{{
myWxBitmap = wx.EmptyBitmap( myIcon.GetWidth(), myIcon.GetHeight() )
myWxBitmap.CopyFromIcon( myIcon )
}}}
 . There seem to be some missing wx functions. I'm not sure if these are available at a lower level of abstraction for the C people, but anyway, here's what hopefully will show up some day :

wxBitmap to string data :

 . Must convert to a wx.Image then call GetData().

Python string of binary data or wx.Image to wxCursor :

 . Should be an overridden constructor available, not yet.

wx.Icon to Python string of binary data or wx.Image :

 . To allow for editing of icons, this would be required.

wxCursor to Python string of binary data or wxImage :

Again, to allow for editing cursors.  Would also need methods to get the current hot spot. wxImage to wxIcon -- See DATA to wxIcon above, either one would be fine, but would be nice to have the complete set.

== PIL (Python Imaging Library) ==
 . PIL can be used with wxPython if more advanced image processing needs are required beyond those built into wxPython. Binary string image data can be created using PIL Image objects with '''.convert()''' and '''.tostring()''' as show in the example below.  Note the use of the '''.size''' attribute of the PIL Image to create the properly sized empty wxImage object.

{{{#!python
import PIL.Image    # The fundamental PIL library module.
import Win32IconImagePlugin     # Necessary for PIL to properly read any  transparency in .ICO files.

import wx

#------------------------------------------------------------------------------

def BitmapFromFile( imgFilename ) :
    """ The following PIL image conversion must first go to a wx.Image.
    The wx.Image is always finally converted to a wx.Bitmap regardless of whether or not
    there is any image transparency information to be handled.
    This is because only a wxBitmap can be directly displayed - a wxImage can't !

    The module Win32IconImagePlugin.py must be imported to get PIL to properly read
    paletted images with a mask (binary valued transparency). All .ICO and some .PNG files
    may have paletted image data with mask transparency. See:

    Win32IconImagePlugin - Alternate PIL plugin for dealing with Microsoft .ico files.
    http://code.google.com/p/casadebender/wiki/Win32IconImagePlugin
    """
    pilImg = PIL.Image.open( imgFilename )

    # The following is equivalent to "wxImg = wx.EmptyImage( pilImg.size[0], pilImg.size[1] )".
    wxImg = wx.EmptyImage( *pilImg.size )   # Always created with no transparency plane.

    # Determine if the image file has any inherent transparency.
    pilMode = pilImg.mode     # Will usually be either "RGB" or "RGBA", but may be others.
    pilHasAlpha = pilImg.mode[-1] == 'A'
    if pilHasAlpha :

        # First extract just the RGB data from the data string and insert it into wx.Image .
        pilRgbStr = pilImg.convert( 'RGB').tostring()
        wxImg.SetData( pilRgbStr )

        # To convert to a wx.Image with alpha the pilImg mode needs to be "RGBA".
        # So, add an alpha layer even if the original file image doesn't have any transparency info.
        # If the file image doesn't have any transparency, the resulting wx.Image (and, finally, the wx.Bitmap)
        # will be 100% opaque just like the file image.
        pilImgStr = pilImg.convert( 'RGBA' ).tostring()    # Harmless if original image mode is already "RGBA".

        # Now, extract just the alpha data and insert it.
        pilAlphaStr = pilImgStr[3::4]    # start at byte index 3 with a stride (byte skip) of 4.
        wxImg.SetAlphaData( pilAlphaStr )

    #end if

    wxBmap = wxImg.ConvertToBitmap()     # Equivalent result:   wxBmap = wx.BitmapFromImage( wxImg )
    return wxBmap

#end def
}}}
Notes:  If a GIF file with a mask is read, PIL will automatically convert the mask to binary-valued alpha transparency. This is usually suitable for display purposes. Neither wx nor PIL can properly write a .ICO file with mask transparency. This is probably fine since it's better to write all non-photographic image files in .PNG format.

== NumPy ==
 . This example shows the creation of a bitmap using a [[http://numpy.org|NumPy]] array as the data source.  Note that NumPy uses reversed column-row ordering compared to wxPython, so you'll need to make sure that you generate images using height, width, not width, height coordinates.  Also note the use of the 'uint8' data type for image data in RGB format.

{{{#!python
import wx, numpy

def GetBitmap( self, width=32, height=32, colour = (0,0,0) ):
        array = numpy.zeros( (height, width, 3),'uint8')
        array[:,:,] = colour
        image = wx.EmptyImage(width,height)
        image.SetData( array.tostring())
        wxBitmap = image.ConvertToBitmap()       # OR:  wx.BitmapFromImage(image)
        return wxBitmap
}}}
=== Slicing ===
NumPy's slicing notation, for our purposes, works as follows:  {{{ [ rowStart: rowEnd, columnStart: columnEnd, colourPlanes ] }}} To assign a single colour to the entire image: {{{ array[:,:] = (r,g,b) }}} To assign a value to the entire red bit plane: {{{ array[:,:,0] = 255 }}} To assign a colour to the first row: {{{ array[ 0 ] = (r,g,b ) }}}

=== Examples ===
This example shows use of NumPy's (extended) slicing notation to alter an in-memory image.  Note that the slice notation allows for standard negative-value index semantics.  Also note the accommodating nature of the assignment operation.  Assigning a three-tuple to a row sets every value in the row, while assigning a list of three-tuples will set each value individually (and raise an error if the number of items is incorrect).

{{{#!python
import wx, numpy

def GetBitmap( self, width=32, height=32, colour=(128, 128, 128), border=5, borderColour=(255, 255, 255) ):
    """
    Creates a bitmap with a border.
    """
    array = numpy.zeros( (height, width, 3), 'uint8' )
    array[ border:-border, border:-border, : ] = colour
    array[ :border, :, : ] = borderColour
    array[ -border:, :, : ] = borderColour
    array[ :, :border, :] = borderColour
    array[ :, -border:, : ] = borderColour
    image = wx.EmptyImage( width, height )
    image.SetData( array.tostring() )
    return image.ConvertToBitmap()    # OR:  wx.BitmapFromImage( image )
}}}
This example creates a horizontal gradient between two colours.  Note that NumPy is automatically converting from float to uint8 data type in the assignment to array, because of the slice indexing.  Without the indexing, array would just get overwritten to point to a different numpy array instead of assigning data within the existing one.

{{{#!python
import numpy as np

def GetBitmap( self, width=640, height=480, leftColour=(255,128,0), rightColour=(64,0,255) ):
        """
        Create a horizontal gradient
        """
        array = np.zeros( (height, width, 3), 'uint8' )

        # alpha is a one dimensional array with a linear gradient from 0.0 to 1.0
        alpha = np.linspace( 0., 1., width )

        # This uses alpha to linearly interpolate between leftColour and rightColour
        colourGradient = np.outer(alpha, leftColour) + np.outer( (1.-alpha), rightColour )

        # NumPy's broadcasting rules will assign colourGradient to every row of the destination array
        array[ :, :, : ] = colourGradient
        image = wx.EmptyImage( width, height )
        image.SetData( array.tostring() )
        wxBitmap = wx.BitmapFromImage( image )    # OR:  image.ConvertToBitmap()
        return wxBitmap
}}}
== Screen Capture ==
This example captures the client area of a frame to a wxBitmap object (and from there, a file).  Note that there is no error checking done here.  Should likely use Ok() or something to check each context.  I'm not sure what would happen if this were called before the first painting of the screen, likely the context would have the desktop or something in it. Note: code below only captures the client area of the window.  Tagore notes that you can get the whole window with a wx.WindowDC and arbitrary parts of the screen with a wx.ScreenDC.

{{{#!python
def OnSaveToFile( self, event ):
        context = wx.ClientDC( self )
        memory = wx.MemoryDC( )
        x, y = self.ClientSize
        bitmap = wx.EmptyBitmap( x, y, -1 )
        memory.SelectObject( bitmap )
        memory.Blit( 0, 0, x, y, context, 0, 0)
        memory.SelectObject( wx.NullBitmap)
        bitmap.SaveFile( 'test.bmp', wx.BITMAP_TYPE_BMP )
}}}
== A Flexible Screen Capture App ==
Here's a general screen capture module and a demo app that first captures the whole primary screen, then captures 4 smaller portions of it.

[[attachment:ScreenShotWX.py]]

[[attachment:ScreenShotWX_Demo.py]]

{{{#!python
def ScreenCapture( captureStartPos, captureBmapSize, debug=False ):
    """
    General Desktop screen portion capture - partial or entire Desktop.

    My particular screen hardware configuration:
        wx.Display( 0 ) refers to the primary  Desktop display monitor screen.
        wx.Display( 1 ) refers to the extended Desktop display monitor screen (above the primary screen).

    Any particular Desktop screen size is :
        screenRect = wx.Display( n ).GetGeometry()

    Different wx.Display's in a single system may have different dimensions.
    """

    # A wx.ScreenDC provides access to the entire Desktop.
    # This includes any extended Desktop monitor screens that are enabled in the OS.
    scrDC = wx.ScreenDC()         # MSW HAS BUG:  DOES NOT INCLUDE ANY EXTENDED SCREENS.
    scrDcSize = scrDC.Size
    scrDcSizeX, scrDcSizeY = scrDcSize

    # Cross-platform adaptations :
    scrDcBmap     = scrDC.GetAsBitmap()
    scrDcBmapSize = scrDcBmap.GetSize()
    if debug :
        print 'DEBUG:  Size of scrDC.GetAsBitmap() ', scrDcBmapSize

    # Check if scrDC.GetAsBitmap() method has been implemented on this platform.
    if   not scrDcBmap.IsOk() :      # Not implemented :  Get the screen bitmap the long way.

        if debug :
            print 'DEBUG:  Using memDC.Blit() since scrDC.GetAsBitmap() is nonfunctional.'

        # Create a new empty (black) destination bitmap the size of the scrDC.
        scrDcBmap = wx.EmptyBitmap( *scrDcSize )    # Overwrire the invalid original assignment.
        scrDcBmapSizeX, scrDcBmapSizeY = scrDcSize

        # Create a DC tool that is associated with scrDcBmap.
        memDC = wx.MemoryDC( scrDcBmap )

        # Copy (blit, "Block Level Transfer") a portion of the screen bitmap
        #   into the returned capture bitmap.
        # The bitmap associated with memDC (scrDcBmap) is the blit destination.

        memDC.Blit( 0, 0,                           # Copy to this start coordinate.
                    scrDcBmapSizeX, scrDcBmapSizeY, # Copy an area this size.
                    scrDC,                          # Copy from this DC's bitmap.
                    0, 0,                    )      # Copy from this start coordinate.

        memDC.SelectObject( wx.NullBitmap )     # Finish using this wx.MemoryDC.
                                                # Release scrDcBmap for other uses.
    else :

        if debug :
            print 'DEBUG:  Using scrDC.GetAsBitmap()'

        # This platform has scrDC.GetAsBitmap() implemented.
        scrDcBmap = scrDC.GetAsBitmap()     # So easy !  Copy the entire Desktop bitmap.

        if debug :
            print 'DEBUG:  scrDcBmap.GetSize() ', scrDcBmap.GetSize()

    #end if

    return scrDcBmap.GetSubBitmap( wx.RectPS( captureStartPos, captureBmapSize ) )

#end ScreenCapture def
}}}
In the application all five captured wxBitmap objects are saved to PNG files.

The wx.ScreenDC treats the entire Desktop screen as a single seamless conglomerate of all exiting wx.Display() areas. Negative coordinate values relative to the main Desktop screen are allowed. Negative ordinate values must be used to capture  any portion of an extension monitor screen to the left of or above the primary monitor screen (the one with the Taskbar). For example, I have two monitors where the extension monitor is configured to be directly above the main monitor. I have set both monitors to 1280x800 resolution. To capture the just the whole extended screen :

{{{#!python
    screenWid = wx.SystemSettings.GetMetric( wx.SYS_SCREEN_X )
    screenHgt = wx.SystemSettings.GetMetric( wx.SYS_SCREEN_Y )
    captureSize = (screenWid, screenHgt*2)  # Both screens are set to be the same size.
    wxBitmap = ScreenCapture( startPos, captureSize )
}}}
Other wxPython add-on packages can take arbitrarily sized screen shots, too, such as ImageMagick and PIL. [[http://www.pythonware.com/products/pil/|Python Imaging Library]]:

[[attachment:DesktopScreenShotPIL.py]]      -- Ray Pasco  ( AKA WinCrazy )

== Write Text to a Bitmap ==
Writing text into a bitmap is done by creating a context then using the context's {{{DrawText}}} method to do the actual drawing.  A simple example:

{{{#!python
import wx

def SetDcContext( memDC, font=None, color=None ):
    if font:
        memDC.SetFont( font )
    else:
        memDC.SetFont( wx.NullFont )

    if color:
        memDC.SetTextForeground( color )

#end def

def WriteTextOnBitmap( text, bitmap, pos=(0, 0), font=None, color=None) :
    """
    Simple write into a bitmap doesn't do any checking.
    """
    memDC = wx.MemoryDC()
    SetDcContext( memDC, font, color )
    memDC.SelectObject( bitmap )
    try:
        memDC.DrawText( text, pos[0], pos[1])
    except :
        pass

    memDC.SelectObject( wx.NullBitmap )

    return bitmap

#end def
}}}
 . One of the things you might want to use this for is creating "button labels" for {{{wx.BitmapButtons}}}.  The following utility function provides basic centred-text (potentially multi-line) captions for your bitmaps.  It also demonstrates the use of the context's {{{GetTextExtent}}} method to perform centring of the text:

{{{#!python
import wx

MINIMUMFONTSIZE = 4

def WriteCaptionOnBitmap( text, bitmap, font=None, margins = (2,2), color=None ):
    """
    Write the given caption (text) into the bitmap
    using the font (or default if not given) with the
    margins given.  Will try to make sure the text fits
    into the bitmap.
    """
    memory = wx.MemoryDC( )
    font = font or memory.GetFont()
    textLines = text.split( '\n' )
    fit = False
    while not fit:
        totalWidth=0
        totalHeight = 0
        setLines = []
        for line in textLines:
            if line and line[-1] == '\r':
                line = line[:-1]

            width, height = extents = memory.GetTextExtent( line )
            totalWidth = max( totalWidth,  width )
            totalHeight += height
            setLines.append( (line, extents))
        #end for

        if (totalWidth > (bitmap.GetWidth()- 2*margins[0])  or  \
           (totalHeight > (bitmap.GetHeight()- 2*margins[0]) ) :

            size = font.GetPointSize() - 1
            if size < MINIMUMFONTSIZE:
                fit = True # will overdraw!!!
            else:
                font.SetPointSize( size )
                memory.SetFont( font )
        else:
            fit = True
        #end if

    #end while

    if not setLines:
        return bitmap

    centreX, centreY = (bitmap.GetWidth()/2), (bitmap.GetHeight()/2)
    x, y = centreX-(totalWidth/2), centreY-(totalHeight/2)
    memory.SelectObject( bitmap )
    SetMemDcContext( memory, font, color)
    for line, (deltaX, deltaY) in setLines:
            x = centreX - (deltaX/2)
            memory.DrawText( line, x, y,)
            y += deltaY
    memory.SelectObject( wxNullBitmap)
    return bitmap


def SetMemDcContext( memory, font=None, color=None ) :

    if font:
        memory.SetFont( font )
    else:
        memory.SetFont( wx.NullFont )

    if color:
        memory.SetTextForeground( color )

#end def
}}}
Since transparency is a bit tricky, here is another example.  (Which unlike the above, works for me).

In this example two bitmaps are created. One is completely white (oldPix) the other one completely black (newPix).  Then a red box is drawn on the black bitmap. Now the black color in newPix is masked and then newPix is copied  over oldPix (the white one). The result is, that only the red box is copied.

{{{#!python
import wx

class Test(wx.App):
    def OnInit(self):
        oldPix  = wx.EmptyBitmap(300, 300)
        newPix  = wx.EmptyBitmap(300, 300)
        mem = wx.MemoryDC()
        mem.SelectObject(oldPix)
        mem.Clear()                       # The images have to be cleared
        mem.SelectObject(newPix)          # because wxEmptyBitmap only
        mem.SetBackground(wx.BLACK_BRUSH)  # allocates the space
        mem.Clear()

        # We now have a black and a white image
        # Next we plot a white box in the middle of the black image

        mem.SetPen(wx.RED_PEN)
        mem.DrawLines(((100, 200), (100, 100), (200, 100), (200,200), (100,200)))

        mem.SelectObject(oldPix)
        newPix.SetMask(wxMaskColour(newPix, wx.BLACK))
        mem.DrawBitmap(newPix, 0, 0, 1)

        oldPix.SaveFile("oldPix.bmp", wx.BITMAP_TYPE_BMP)
        newPix.SaveFile("newPix.bmp", wx.BITMAP_TYPE_BMP)
        return True

app = Test(redirect=False)
app.MainLoop()
}}}
This is a complete wxPython app, so just run it and have a look at the created Bitmaps oldPix.bmp and  newPix.bmp for the results.  -- Nikolai Hlubek

== PythonMagick (a 16-bit Imaging Library) ==
Here is a short but complete PythonMagick/wxPython program. The program uses wxPython GUI, loads an image, displays the image, and does a simple image processing operation (threshold). Various conversions between PythonMagick, PIL, and wxPython images are available on the [[http://www.procoders.net/moinmoin/PythonMagick|PythonMagick]] web site.

See the PythonMagick page for a greater description of PythonMagick.

Note that PythonMagick presently only has a Windows installer.

{{{#!python
from wxPython import wx
import PythonMagick

ID_FILE_OPEN = wx.wxNewId()
ID_FILE_EXIT  = wx.wxNewId()
ID_THRESHOLD = wx.wxNewId()

class ImagePanel(wx.wxPanel):
    def __init__(self, parent, id):
        wx.wxPanel.__init__(self, parent, id)
        self.image = None  # wxPython image
        wx.EVT_PAINT(self, self.OnPaint)

    def display(self, magickimage):
        self.image = self.convertMGtoWX(magickimage)
        self.Refresh(True)

    def OnPaint(self, evt):
        dc = wx.wxPaintDC(self)
        if self.image:
            dc.DrawBitmap(self.image.ConvertToBitmap(), 0,0)

    def convertMGtoWX(self, magickimage):
        img = PythonMagick.Image(magickimage)  # make copy
        img.depth = 8        #  change depth only for display
        img.magick = "RGB"
        data = img.data
        wximg = wx.wxEmptyImage(img.columns(), img.rows())
        wximg.SetData(data)
        return wximg


class mtFrame(wx.wxFrame):
    def __init__(self, parent, ID, title):
        wx.wxFrame.__init__(self, parent, ID, title, wx.wxDefaultPosition, wx.wxSize(500, 400))

        self.iPanel = ImagePanel(self, -1)
        self.im = None  # Magick image

        ## Construct "File" menu
        self.menuBar = wx.wxMenuBar()
        self.menuFile = wx.wxMenu()
        self.menuFile.Append(ID_FILE_OPEN, "&Open image","")
        wx.EVT_MENU(self, ID_FILE_OPEN, self.OnOpen)
        self.menuFile.AppendSeparator()
        self.menuFile.Append(ID_FILE_EXIT, "E&xit", "")
        wx.EVT_MENU(self, ID_FILE_EXIT,  self.OnExit)
        self.menuBar.Append(self.menuFile, "&File");

        ## Construct "Process" menu
        self.menuProcess = wx.wxMenu()
        self.menuProcess.Append(ID_THRESHOLD, "Threshold", "")
        wx.EVT_MENU(self, ID_THRESHOLD,  self.OnThreshold)

        self.menuBar.Append(self.menuProcess, "&Process")
        self.SetMenuBar(self.menuBar)

    def OnOpen(self, event):
        fd = wx.wxFileDialog(self, "Open Image", "", "", "*.*", wx.wxOPEN)

        if fd.ShowModal() == wx.wxID_OK:
            self.loadImage(fd.GetPath())
        fd.Destroy()

    def loadImage(self, path):
        try:
            self.im = PythonMagick.Image(path)
            self.iPanel.display(self.im)
        except IOError:
            print "can't open the file"

    ##-------------- Process ------------------------

    def OnThreshold(self, event):
        self.im = self.Threshold(self.im, 0.5)
        self.iPanel.display(self.im)
        #self.im.write('d:/threshold.tif')

    def Threshold(self, image, threshold):
        """
        Threshold image. Input threshold is normalized (0-1.0)
        """
        img = PythonMagick.Image(image) # copy
        img.threshold(threshold *65535.0)
        return img

    ##-----------------------------------------------

    def OnCloseWindow(self, event):
        self.Destroy()

    def OnExit(self, event):
        self.Close(True)

#---------------------------------------------------------------------------

class mtApp(wx.wxApp):
    def OnInit(self):
        frame = mtFrame(wx.NULL, -1, "MagickSimple1")
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

app = mtApp(0)
app.MainLoop()
}}}
-Bob Klimek 9-23-03

= Thanks =
Another word of thanks. I used the pil --> image with alpha tricks learned from this page.    \d