Hi,
I tried to understand how can I do a zooming on a image using a Panel. I tried with functions resize (for the image) and blit (to paste from a MemoryDC to the current DC). A problem always occurs when I zoom and I didn't find what is wrong in my code: the image moves very far from the zooming point and I cannot stay centered.
Maybe if I give you a PART of my source code, you will be able to understand what I mean (my script is inspired from the floatCanvas.py file given with wxPython).
Thanks,
Mathieu
class GelCanvas(wxPanel):
def __init__(self, parent, id=-1, size=wxDefaultSize, item=None):
wxPanel.__init__(self, parent, id, wxPoint(-1,-1), size, wxSUNKEN_BORDER)
self.image = None
self.screenImage = None
# EVT_PAINT(self, self.OnPaint)
EVT_SIZE(self, self.OnPaint)
EVT_LEFT_DOWN(self, self.LeftButtonEvent)
EVT_LEFT_UP(self, self.LeftButtonEvent)
EVT_RIGHT_DOWN(self, self.RightButtonEvent)
EVT_MOTION(self, self.LeftButtonEvent)
self.AspectRatio = 1.0
self.PanelSize = array(self.GetSize(),Float)
self.Scale = 1
self.ViewPortCenter= array( (0,0), Float)
self.TransformVector = array( (1,1), Float) # default Transformation
self.GUIMode = None
self.StartRBBox = None
self.StartMove = None
def OnPaint(self, event):
self.Draw()
def Draw(self):
ScreenDC = wxClientDC(self)
if self.screenImage:
tmp_dc = wxMemoryDC()
tmp_dc.BeginDrawing()
tmp_dc.SelectObject(self.screenImage)
tmp_dc.EndDrawing()
ScreenDC.Clear()
ScreenDC.Blit( 0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight(), tmp_dc,
(self.ViewPortCenter[0])*self.TransformVector[0],
(self.ViewPortCenter[1])*(self.TransformVector[1]))
def LeftButtonEvent(self,event):
if self.GUIMode:
if self.GUIMode == "ZoomIn":
if event.LeftDown():
self.StartRBBox = (event.GetX(),event.GetY())
self.PrevRBBox = None
elif event.Dragging() and event.LeftIsDown() and self.StartRBBox:
x0,y0 = self.StartRBBox
x1,y1 = event.GetX(),event.GetY()
w, h = abs(x1-x0),abs(y1-y0)
w = max(w,int(h*self.AspectRatio))
h = int(w/self.AspectRatio)
x_c, y_c = (x0+x1)/2 , (y0+y1)/2
dc = wxClientDC(self)
dc.BeginDrawing()
dc.SetPen(wxPen('WHITE', 2,wxSHORT_DASH))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.SetLogicalFunction(wxXOR)
if self.PrevRBBox:
dc.DrawRectangle(*self.PrevRBBox)
dc.DrawRectangle(x_c-w/2,y_c-h/2,w,h)
self.PrevRBBox = (x_c-w/2,y_c-h/2,w,h)
dc.EndDrawing()
elif event.LeftUp() and self.StartRBBox :
EndRBBox = (event.GetX(),event.GetY())
StartRBBox = self.StartRBBox
if abs(StartRBBox[0] - EndRBBox[0]) > 10 and abs(StartRBBox[1] - EndRBBox[1]) > 10:
EndRBBox = self.PixelToWorld(EndRBBox)
StartRBBox = self.PixelToWorld(StartRBBox)
Center = self.WorldToPixel(abs(StartRBBox-EndRBBox))
Factor = (max(EndRBBox[0],StartRBBox[0]) - min(EndRBBox[0],StartRBBox[0])) / (self.image.GetWidth()*self.TransformVector[0])
self.Zoom(Factor, Center)
else:
Center = (StartRBBox)
self.Zoom(1.5,Center)
self.StartRBBox = None
if self.GUIMode == "ZoomOut":
if event.LeftDown():
Center = self.WorldToPixel((event.GetX(),event.GetY()))
self.Zoom(1/1.5,Center)
elif self.GUIMode == "Move":
if event.LeftDown():
self.StartMove = array((event.GetX(),event.GetY()))
self.PrevMoveBox = None
elif event.Dragging() and event.LeftIsDown() and self.StartMove:
x_1,y_1 = event.GetX(),event.GetY()
w, h = self.GetSize()
x_tl, y_tl = x_1 - self.StartMove[0], y_1 - self.StartMove[1]
dc = wxClientDC(self)
dc.BeginDrawing()
dc.SetPen(wxPen('WHITE', 1,))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.SetLogicalFunction(wxXOR)
if self.PrevMoveBox:
dc.DrawRectangle(*self.PrevMoveBox)
dc.DrawRectangle(x_tl,y_tl,w,h)
self.PrevMoveBox = (x_tl,y_tl,w,h)
dc.EndDrawing()
elif event.LeftUp() and self.StartMove:
StartMove = self.StartMove
EndMove = array((event.GetX(),event.GetY()))
if sum((StartMove-EndMove)**2) > 16:
self.Move(StartMove-EndMove,'Pixel')
self.StartMove = None
def PixelToWorld(self,Points):
return (((array(Points,Float) - (self.PanelSize/2))/self.TransformVector) + self.ViewPortCenter)
def WorldToPixel(self,Coordinates):
return (((array(Coordinates,Float) - self.ViewPortCenter)*self.TransformVector) + (self.PanelSize/2)).astype('i')
def PixelToImage(self, Points):
ViewPortOrigin = self.ViewPortCenter - self.PanelSize/2
return (int(Points[0]/self.TransformVector[0] + ViewPortOrigin[0]) , int(Points[1]/self.TransformVector[0] - ViewPortOrigin[1]))
def ImageToPixel(self, Points):
ViewPortOrigin = (0,0)
return ((Points[0] - ViewPortOrigin[0])*self.TransformVector[0] , (Points[1] + ViewPortOrigin[1])*self.TransformVector[1])
def Move(self,shift,CoordType):
shift = array(shift,Float)
if CoordType == 'Panel':# convert from panel coordinates
shift = shift * array((-1,-1),Float) *self.PanelSize/self.TransformVector
elif CoordType == 'Pixel': # convert from pixel coordinates
shift = shift/self.TransformVector
elif CoordType == 'World': # No conversion
pass
self.ViewPortCenter = self.ViewPortCenter + shift
self.Draw()
def Zoom(self,factor,center = None):
self.Scale = self.Scale*factor
self.TransformVector = array((self.Scale,self.Scale),Float)
self.screenImage = self.image.Scale(self.image.GetWidth()*self.TransformVector[0],self.image.GetHeight()*self.TransformVector[1]).ConvertToBitmap()
center = (-(self.GetSize().GetWidth()/2 - center[0]), -(self.GetSize().GetHeight()/2 - center[1]))
print "center: ", center, " ViewPortCenter", self.ViewPortCenter
self.Move(center, 'Pixel')
self.Draw()