~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/demo/RawBitmapAccess.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import wx
 
2
 
 
3
# use the numpy code instead of the raw access code for comparison
 
4
USE_NUMPY = False
 
5
 
 
6
# time the execution of making a bitmap?
 
7
TIMEIT = False
 
8
 
 
9
# how big to make the bitmaps
 
10
DIM = 100
 
11
 
 
12
# should we use a wx.GraphicsContext for painting?
 
13
TEST_GC = False
 
14
 
 
15
#----------------------------------------------------------------------
 
16
# attempt to import a numeric module if requested to
 
17
 
 
18
if USE_NUMPY:
 
19
    try:
 
20
        import numpy
 
21
        def makeByteArray(shape):
 
22
            return numpy.empty(shape, numpy.uint8)
 
23
        numtype = 'numpy'
 
24
    except ImportError:
 
25
        try:
 
26
            import numarray
 
27
            def makeByteArray(shape):
 
28
                arr =  numarray.array(shape=shape, typecode='u1')
 
29
                arr[:] = 0
 
30
                return arr
 
31
            numtype = 'numarray'
 
32
        except ImportError:
 
33
            USE_NUMPY = False
 
34
 
 
35
 
 
36
#----------------------------------------------------------------------
 
37
 
 
38
class TestPanel(wx.Panel):
 
39
    def __init__(self, parent, log):
 
40
        self.log = log
 
41
        wx.Panel.__init__(self, parent, -1)
 
42
        self.Bind(wx.EVT_PAINT, self.OnPaint)
 
43
 
 
44
        if TIMEIT:
 
45
            import timeit
 
46
            timeit.s = self # Put self in timeit's global namespace as
 
47
                            # 's' so it can be found in the code
 
48
                            # snippets being tested.
 
49
            if not USE_NUMPY:
 
50
                t = timeit.Timer("bmp = s.MakeBitmap(10, 20, 30)")
 
51
            else:
 
52
                t = timeit.Timer("bmp = s.MakeBitmap2(10, 20, 30)")
 
53
            log.write("Timing...\n")
 
54
            num = 100
 
55
            tm = t.timeit(num)
 
56
            log.write("%d passes in %f seconds ==  %f seconds per pass " % 
 
57
                  (num, tm, tm/num))
 
58
            
 
59
        if not USE_NUMPY:
 
60
            log.write("using raw access\n")
 
61
            self.redBmp   = self.MakeBitmap(178,  34,  34)
 
62
            self.greenBmp = self.MakeBitmap( 35, 142,  35)
 
63
            self.blueBmp  = self.MakeBitmap(  0,   0, 139)
 
64
        else:
 
65
            log.write("using %s\n" % numtype)
 
66
            self.redBmp   = self.MakeBitmap2(178,  34,  34)
 
67
            self.greenBmp = self.MakeBitmap2( 35, 142,  35)
 
68
            self.blueBmp  = self.MakeBitmap2(  0,   0, 139)
 
69
 
 
70
 
 
71
    def OnPaint(self, evt):
 
72
        dc = wx.PaintDC(self)
 
73
        if not TEST_GC:
 
74
            dc.DrawBitmap(self.redBmp,    50,  50, True)
 
75
            dc.DrawBitmap(self.greenBmp, 110, 110, True)
 
76
            dc.DrawBitmap(self.blueBmp,  170,  50, True)
 
77
            self.log.write("using wx.DC\n")
 
78
        else:
 
79
            gc = wx.GraphicsContext.Create(dc)
 
80
            gc.DrawBitmap(self.redBmp, 50, 50, DIM,DIM)
 
81
            gc.DrawBitmap(self.greenBmp, 110, 110, DIM,DIM)
 
82
            gc.DrawBitmap(self.blueBmp,  170,  50, DIM,DIM)
 
83
            self.log.write("using wx.GraphicsContext\n")
 
84
 
 
85
    def MakeBitmap(self, red, green, blue, alpha=128):
 
86
        # Create the bitmap that we will stuff pixel values into using
 
87
        # the raw bitmap access classes.
 
88
        bmp = wx.EmptyBitmap(DIM, DIM, 32)
 
89
 
 
90
        # Create an object that facilitates access to the bitmap's
 
91
        # pixel buffer
 
92
        pixelData = wx.AlphaPixelData(bmp)
 
93
        if not pixelData:
 
94
            raise RuntimeError("Failed to gain raw access to bitmap data.")
 
95
 
 
96
        # We have two ways to access each pixel, first we'll use an
 
97
        # iterator to set every pixel to the colour and alpha values
 
98
        # passed in.
 
99
        for pixel in pixelData:
 
100
            pixel.Set(red, green, blue, alpha)
 
101
 
 
102
        # This block of code is another way to do the same as above,
 
103
        # but with the accessor interface instead of the Python
 
104
        # iterator.  It is a bit faster than the above because it
 
105
        # avoids the iterator/generator magic, but it is not nearly as
 
106
        # 'clean' looking ;-)
 
107
        #pixels = pixelData.GetPixels()
 
108
        #for y in xrange(DIM):
 
109
        #    pixels.MoveTo(pixelData, 0, y)
 
110
        #    for x in xrange(DIM):
 
111
        #        pixels.Set(red, green, blue, alpha)
 
112
        #        pixels.nextPixel()
 
113
 
 
114
 
 
115
 
 
116
        # Next we'll use the pixel accessor to set the border pixels
 
117
        # to be fully opaque
 
118
        pixels = pixelData.GetPixels()
 
119
        for x in xrange(DIM):
 
120
            pixels.MoveTo(pixelData, x, 0)
 
121
            pixels.Set(red, green, blue, wx.ALPHA_OPAQUE)
 
122
            pixels.MoveTo(pixelData, x, DIM-1)
 
123
            pixels.Set(red, green, blue, wx.ALPHA_OPAQUE)
 
124
        for y in xrange(DIM):
 
125
            pixels.MoveTo(pixelData, 0, y)
 
126
            pixels.Set(red, green, blue, wx.ALPHA_OPAQUE)
 
127
            pixels.MoveTo(pixelData, DIM-1, y)
 
128
            pixels.Set(red, green, blue, wx.ALPHA_OPAQUE)
 
129
            
 
130
        return bmp
 
131
 
 
132
 
 
133
    def MakeBitmap2(self, red, green, blue, alpha=128):
 
134
        # Make an array of bytes that is DIM*DIM in size, with enough
 
135
        # slots for each pixel to have a RGB and A value
 
136
        arr = makeByteArray( (DIM,DIM, 4) )
 
137
 
 
138
        # just some indexes to keep track of which byte is which
 
139
        R, G, B, A = range(4)
 
140
 
 
141
        # initialize all pixel values to the values passed in
 
142
        arr[:,:,R] = red
 
143
        arr[:,:,G] = green
 
144
        arr[:,:,B] = blue
 
145
        arr[:,:,A] = alpha
 
146
 
 
147
        # Set the alpha for the border pixels to be fully opaque
 
148
        arr[0,     0:DIM, A] = wx.ALPHA_OPAQUE  # first row
 
149
        arr[DIM-1, 0:DIM, A] = wx.ALPHA_OPAQUE  # last row
 
150
        arr[0:DIM, 0,     A] = wx.ALPHA_OPAQUE  # first col
 
151
        arr[0:DIM, DIM-1, A] = wx.ALPHA_OPAQUE  # last col
 
152
 
 
153
        # finally, use the array to create a bitmap
 
154
        bmp = wx.BitmapFromBufferRGBA(DIM, DIM, arr)
 
155
        return bmp
 
156
    
 
157
           
 
158
        
 
159
#----------------------------------------------------------------------
 
160
 
 
161
def runTest(frame, nb, log):
 
162
    win = TestPanel(nb, log)
 
163
    return win
 
164
 
 
165
#----------------------------------------------------------------------
 
166
 
 
167
 
 
168
 
 
169
overview = """<html><body>
 
170
<h2><center>Raw Bitmap Access</center></h2>
 
171
 
 
172
wx.NativePixelData and wx.AlphaPixelData provide a cross-platform way
 
173
to access the platform-specific pixel buffer within a wx.Bitmap.  They
 
174
provide both a random access method, and an iterator interface.
 
175
 
 
176
<p>Unfortunately, although these classes are convienient ways to access
 
177
and update the contents of a wx.Bitmap, we lose most of the efficiency
 
178
of the C++ classes by requiring one or more Python-to-C++ transitions
 
179
for each pixel.  In fact it can be <b>much</b> slower than the other
 
180
ways of creating a bitmap from scratch, especially now that
 
181
wx.BitmapFromBuffer exists and can save the time needed to copy from a
 
182
wx.Image.
 
183
 
 
184
<p>To see this difference for yourself this module has been
 
185
instrumented to allow you to experiment with using either the raw
 
186
access or numpy/numarray, and also to time how long it takes to create
 
187
100 bitmaps like you see on the screen.  Simply edit this module in
 
188
the \"Demo Code\" tab and set TIMEIT to True and then watch
 
189
the log window when the sample is reloaded.  To try numpy or numarray
 
190
(if you have them installed) then set USE_NUMPY to True as well, and
 
191
watch the log window again. On my machines there is about <b>an
 
192
order of magnitude</b> difference between the raw access functions
 
193
and using a numarray.array with wx.BitmapFromBufferRGBA!  Almost
 
194
another order of magnitude improvement can be gained with using the
 
195
new numpy module!
 
196
 
 
197
</body></html>
 
198
"""
 
199
 
 
200
 
 
201
 
 
202
if __name__ == '__main__':
 
203
    import sys,os
 
204
    import run
 
205
    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
 
206