[wxPython-users] Another question about bitmaps
Andrea Gavana
andrea.gavana at gmail.com
Fri Jun 29 14:27:59 PDT 2007
Hi Brian,
On 6/30/07, Brian Wolf wrote:
> I'm still struggling with putting a bitmap on a panel, and then giving
> the user a mechanism to zoom in / zoom out. So far, I've contructed a
> "popup" window (wx.Frame) that contains a panel on which the bitmap
> should be drawn. The panel also contains a slider which is supposed to
> let the user increase or decrease the size of the bitmap (for instance,
> a photo).
>
> I've not been able to get PaintDC or ScreenDC to work effectively. A
> staticbitmap is not so flexible. PIL provides a .resize() function that
> returns another bitmap, but integrating wxPyton and PIL is not easy.
The handler you want to implement is an OnPaint method which tkes care
of the wx.EVT_PAINT event, plus some other things. Please try the
attached file: it's not a complete application (it doesn't work as-is
out of the box), but it should get you started.
It has zoom capabilities (via mouse-wheel), shadows beneath images
(generated using PIL) and other goodies. It's taken directly from my
software "InfinImage", and it uses a wx.ScrolledWindow to display the
image, drawing it in the OnPaint event handler.
HTH.
Andrea.
"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/
-------------- next part --------------
import wx
import Image
import ImageFilter
import math
def BitmapToPil(bitmap):
return ImageToPil(BitmapToImage(bitmap))
def BitmapToImage(bitmap):
return wx.ImageFromBitmap(bitmap)
def PilToBitmap(pil):
return ImageToBitmap(PilToImage(pil))
def PilToImage(pil):
image =3D wx.EmptyImage(pil.size[0], pil.size[1])
image.SetData(pil.convert('RGB').tostring())
return image
def PiltoImageAlpha(pil, alpha=3DTrue):
if alpha:
image =3D apply(wx.EmptyImage, pil.size)
image.SetData(pil.convert( "RGB").tostring())
image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
else:
image =3D wx.EmptyImage(pil.size[0], pil.size[1])
new_image =3D pil.convert('RGB')
data =3D new_image.tostring()
image.SetData(data)
=
return image
def ImageToPil(image):
pil =3D Image.new('RGB',(image.GetWidth(), image.GetHeight()))
pil.fromstring(image.GetData())
return pil
def ImageToBitmap(image):
return image.ConvertToBitmap()
def DropShadow(image, offset=3D(5,5), background=3D0xffffff, shadow=3D0x444=
444, =
border=3D8, iterations=3D3):
"""
Add a gaussian blur drop shadow to an image. =
image - The image to overlay on top of the shadow.
offset - Offset of the shadow from the image as an (x,y) tuple. C=
an be
positive or negative.
background - Background colour behind the image.
shadow - Shadow colour (darkness).
border - Width of the border around the image. This must be wide
enough to account for the blurring of the shadow.
iterations - Number of times to apply the filter. More iterations =
produce a more blurred shadow, but increase processing ti=
me.
"""
# Create the backdrop image -- a box in the background colour with a =
# shadow on it.
totalWidth =3D image.size[0] + abs(offset[0]) + 2*border
totalHeight =3D image.size[1] + abs(offset[1]) + 2*border
back =3D Image.new(image.mode, (totalWidth, totalHeight), background)
# Place the shadow, taking into account the offset from the image
shadowLeft =3D border + max(offset[0], 0)
shadowTop =3D border + max(offset[1], 0)
back.paste(shadow, [shadowLeft, shadowTop, shadowLeft + image.size[0],
shadowTop + image.size[1]])
# Apply the filter to blur the edges of the shadow. Since a small kern=
el
# is used, the filter must be applied repeatedly to get a decent blur.
n =3D 0
while n < iterations:
back =3D back.filter(ImageFilter.BLUR)
n +=3D 1
=
# Paste the input image onto the shadow backdrop =
imageLeft =3D border - min(offset[0], 0)
imageTop =3D border - min(offset[1], 0)
back.paste(image, (imageLeft, imageTop))
return back
class ScrolledImage(wx.ScrolledWindow):
def __init__(self, parent, id=3D-1, pos=3Dwx.DefaultPosition, size=3Dwx=
.DefaultSize):
wx.ScrolledWindow.__init__(self, parent, id, pos, size) =
self.zoom_levels =3D range(8, 1, -1) + [1./r for r in range(1, 9)]
self.zoom_level =3D self.zoom_levels.index(1.)
self.scale =3D 1.
self.size =3D wx.Size(0, 0)
self.wheel =3D 0
self.SetExtraStyle(0)
self.backcolour =3D wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFAC=
E)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
self.MainFrame =3D wx.GetTopLevelParent(self) =
def CalculateShadow(self, image):
=
size =3D image.size
=
if size[0] <=3D 32:
xshadow =3D 3
elif 32 < size[0] <=3D 200:
xshadow =3D 5
elif 200 < size[0] <=3D 600:
xshadow =3D 8
else:
xshadow =3D 10
if size[1] <=3D 32:
yshadow =3D 3
elif 32 < size[1] <=3D 200:
yshadow =3D 5
elif 200 < size[1] <=3D 600:
yshadow =3D 8
else:
yshadow =3D 10
border =3D max(xshadow, yshadow)
return xshadow, yshadow, border =
=
def ShowImage(self, image):
PIL_bitmap =3D Image.open(image)
x, y, border =3D self.CalculateShadow(PIL_bitmap)
=
PIL_bitmap =3D DropShadow(PIL_bitmap, offset=3D(x, y), border=3Dbor=
der)
bmp =3D PilToBitmap(PIL_bitmap)
self.SetScrollbars(1, 1, PIL_bitmap.size[0], PIL_bitmap.size[1], 0,=
0)
size =3D self.GetSize()
xmin =3D (size.x - PIL_bitmap.size[0])/2
ymin =3D (size.y - PIL_bitmap.size[1])/2
=
self.currentbmp =3D bmp
self.size =3D wx.Size(self.currentbmp.GetSize().width*self.scale, s=
elf.currentbmp.GetSize().height*self.scale)
self.SetViewScale(self.zoom_levels[self.zoom_level])
=
self.Refresh()
=
def Zoom(self, dir):
self.zoom_level +=3D dir
if self.zoom_level < 0:
self.zoom_level =3D 0
return
elif self.zoom_level >=3D len(self.zoom_levels):
self.zoom_level =3D len(self.zoom_levels)-1
return
self.SetViewScale(self.zoom_levels[self.zoom_level])
self.MainFrame.bottompanel.SetScrollValue(self.zoom_level)
def OnPaint(self, event):
self.SetScale(1./self.scale,1./self.scale)
dc =3D wx.PaintDC(self)
dc.SetBackground(wx.Brush(self.backcolour))
iw, ih =3D self.size
## if iw < self.windowsize.x or ih < self.windowsize.y:
dc.Clear()
=
self.DoPaint(dc)
del dc
self.SetScale(1., 1.)
=
def DoPaint(self, dc=3DNone):
if dc is None:
dc =3D wx.ClientDC(self)
self.PrepareDC(dc)
iw, ih =3D self.size
xmin =3D (self.windowsize.x - iw)/2
ymin =3D (self.windowsize.y - ih)/2
bm_dc =3D wx.MemoryDC() =
bm_dc.SelectObject(self.currentbmp)
## if xmin >=3D 0 and ymin >=3D 0:
## self.DrawContour(bm_dc)
if xmin < 0:
xmin =3D 0
if ymin < 0:
ymin =3D 0
dc.Blit(xmin*self.scale, ymin*self.scale, iw*self.scale, ih*self.sc=
ale, bm_dc, 0, 0, wx.COPY, True)
bm_dc.SelectObject(wx.NullBitmap)
def DrawContour(self, dc):
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetPen(wx.Pen(wx.BLACK, 2))
dc.DrawRectangle(1, 1, self.currentbmp.GetWidth()-1, self.currentbm=
p.GetHeight()-1)
def OnEraseBackground(self, event):
=
pass
def OnSize(self, event):
iw, ih =3D self.size.width, self.size.height
w, h =3D event.GetSize()
scroll_x =3D w < iw
scroll_y =3D h < ih
scroll =3D scroll_x | scroll_y
x, y =3D self.GetViewStart()
self.SetScrollbars(scroll,scroll,iw,ih,x,y)
self.windowsize =3D wx.Size(w, h)
def SetViewScale(self, scale):
self.SetScale(1.,1.)
self.GetParent().SetSizeHints(-1,-1,-1,-1)
x, y =3D self.GetViewStart()
cw, ch =3D self.GetClientSize()
midx, midy =3D x + cw / 2, y + ch / 2
midx /=3D float(self.size.width)
midy /=3D float(self.size.height)
self.scale =3D scale
self.size =3D wx.Size(self.currentbmp.GetSize().width/self.scale, s=
elf.currentbmp.GetSize().height/self.scale)
iw, ih =3D self.size.width, self.size.height
w, h =3D self.GetSize()
scroll_x =3D w < iw
scroll_y =3D h < ih
x, y =3D self.GetViewStart()
new_midx =3D midx * self.size.width
new_midy =3D midy * self.size.height
x =3D new_midx - cw/2
y =3D new_midy - ch/2
self.SetScrollbars(scroll_x,scroll_y,iw,ih,x,y)
zoom_percent =3D round((1./self.scale)*100, 2)
if zoom_percent =3D=3D math.floor(zoom_percent):
zoom_percent =3D str(zoom_percent).rstrip( '0' )[0:-1]
self.SetScale(self.scale,self.scale)
def OnMouseWheel(self, event):
if event.m_controlDown:
self.wheel +=3D event.GetWheelRotation()
if abs(self.wheel) >=3D event.GetWheelDelta():
if event.GetWheelRotation() < 0:
self.Zoom(-1)
self.wheel+=3D event.GetWheelDelta()
else:
self.Zoom(+1)
self.wheel-=3D event.GetWheelDelta()
else:
iw, ih =3D self.size.width, self.size.height
w, h =3D self.GetSize()
scroll_x =3D w < iw
scroll_y =3D h < ih
if scroll_x or scroll_y: =
event.Skip() =
=20
More information about the wxpython-users
mailing list