Enable crop and zooming in on your digital photograph display form
I wanted to add the ability to zoom into a portion of a photograph on my photo viewer. Below is some code that processes the MouseUp, MouseDown and MouseMove events to add a yellow dotted-dash selection rectangle using a Shape control that the mouse can resize over the desired portion of a picture to crop/zoom.
Using the image control with Stretch set to Isometric means to keep the image’s original proportions (so skinny people stay skinny). That means that if the image control’s aspect ratio (width/height) is different from that of the original picture, either the top/bottom edges or the left/right edges of the image surface will be blank. Thus, calculating the crop rectangle gets a little complicated.
An additional complication arises when the ShowWindow is set to show the form as a top level form. The hWnd needed to draw the image is the client window of the form. WindowFromPoint is called to get the window from an x/y position.
The DrawImagePortionScaled routine of _gdiplus.vcx is called to do the scaling and drawing.
Now I can zoom in on that book on the bookcase in the background of the photo to read the title and author!
PUBLIC x
x=NEWOBJECT("pform")
DEFINE CLASS pform as form
left=00
width=600
height=300
ShowWindow=1
allowoutput=.f.
ADD OBJECT img as myimage
PROCEDURE init
this.img.visible=1
this.img.picture="d:\kids.jpg"
this.img.height=thisform.height
this.img.width=thisform.width
this.visible=1
DECLARE integer ValidateRect IN WIN32API integer, integer
ENDDEFINE
DEFINE CLASS myimage as Image
stretch=1
nState=0
PROCEDURE mousemove(nBut,nShift,x,y)
IF this.nState=1
IF x > thisform.dr.Left
thisform.dr.width=x - thisform.dr.Left
ENDIF
IF y > thisform.dr.Top
thisform.dr.height = y -thisform.dr.Top
ENDIF
ENDIF
PROCEDURE mousedown(nBut,nShift,x,y)
IF this.nState>0
thisform.dr.visible=0
this.picture=this.picture
this.nState=0
RETURN
ENDIF
IF VARTYPE(thisform.dr)='U'
thisform.AddObject("dr","myshape")
ENDIF
thisform.dr.top=y
thisform.dr.left = x
thisform.dr.height=1
thisform.dr.width=1
thisform.dr.visible=1
this.nState=1
PROCEDURE mouseup(nBut,nShift,x,y)
IF this.nState#1
RETURN
ENDIF
this.nState =2
thisform.dr.visible=.f.
thisform.img.picture=thisform.img.picture &&paint over sel rect
SET CLASSLIB TO HOME()+"ffc\_gdiplus"
LOCAL oGraphics as gpGraphics OF (HOME()+"ffc\_gdiplus")
LOCAL oRectDest as gpRectangle OF (HOME()+"ffc\_gdiplus")
LOCAL oImage as gpImage OF (HOME()+"ffc\_gdiplus")
oImage=CREATEOBJECT("gpImage",thisform.img.picture)
oGraphics=CREATEOBJECT("gpgraphics")
wRatio=oImage.ImageHeight/oImage.ImageWidth && 1704/2272 .75
pRatio=thisform.img.Height/thisform.img.Width && 300/600 .5
*Must compensate for Stretch=1 (Isometric)
IF wRatio>pratio
wwidth=thisform.img.height/wRatio
wleft=thisform.img.left+(thisform.img.width - wwidth)/2
wtop=thisform.img.top
wheight=thisform.img.height
oRectSrc=CREATEOBJECT("gpRectangle",;
(thisform.dr.left-wleft)*oImage.ImageWidth/wWidth,;
(thisform.dr.top - thisform.img.top) *oImage.ImageHeight/thisform.img.height,;
thisform.dr.width*oImage.ImageWidth/wWidth,;
thisform.dr.Height * oImage.ImageHeight/thisform.img.height)
ELSE
wwidth=thisform.img.width
wleft=thisform.img.left
wheight=thisform.img.width*wRatio
wTop=thisform.img.top+(thisform.img.height-wheight)/2
oRectSrc=CREATEOBJECT("gpRectangle",;
thisform.dr.left * oImage.ImageWidth/thisform.img.width,;
(thisform.dr.top-wtop) *oImage.ImageHeight/wheight,;
thisform.dr.width * oImage.ImageWidth/thisform.img.width,;
thisform.dr.Height *oImage.ImageHeight/wheight)
ENDIF
oRectDest=CREATEOBJECT("gpRectangle",wleft,wtop,wwidth,wHeight)
hWnd=SYS(2327, SYS(2325, SYS(2326,THISFORM.hwnd))) && From Craig Boyd
oGraphics.CreateFromHWND(hWnd)
oGraphics.DrawImagePortionScaled(oImage,oRectDest,oRectSrc,2)
ValidateRect(hWnd,0)
ENDDEFINE
DEFINE CLASS myshape as Shape
bordercolor=65535
BackStyle=0 && transparent
BorderStyle=4
ENDDEFINE
Comments
Anonymous
August 11, 2005
Calvin,
It's not working when I select an area on the photo. It just flashes and goes back to original image.
p.s. this code solves the code copying and pasting from your post:
_cliptext = STRTRAN(_cliptext,CHR(13)+CHR(13),CHR(13))Anonymous
August 11, 2005
Hi Calvin,
Nice use of GDI+ and a decent example of how to create a rubberband selection feature. As for the Child window of a Visual FoxPro TopLevel form, I detailed this in an FoxTalk 2.0 article that might be of interest to you, a couple of other solutions for getting the child window's hwnd and a link to the GDI+ article...
!* Using only Visual FoxPro 9
Local lnHwnd
lnHwnd = SYS(2327, SYS(2325, SYS(2326,THISFORM.hwnd)))
! Using GetWindow API function
*
#DEFINE GW_CHILD 5
DECLARE LONG GetWindowLong IN User32 LONG HWND, INTEGER nIndex
Local lnHwnd
lnHwnd = IIF(THISFORM.SHOWWINDOW = 2, GetWindow(THISFORM.HWND,GW_CHILD), THISFORM.HWND)
Here's the link for the "GDI+ on VFP 9 Forms" article (the real link is about a mile long, so I'm giving you a tinyurl that points to it)
http://tinyurl.com/bpas8Anonymous
August 11, 2005
The comment has been removedAnonymous
August 11, 2005
If it doesn't work for you, try a larger JPG: apparently it only works with JPGs with my kids in them (about 1 Meg). It's a timing issue: it is working with the smaller JPGs (you might see it flicker) but then a WM_PAINT message is processed which refreshes the original JPG.Anonymous
August 11, 2005
I've modified the code to call ValidateRect so that the WM_PAINT won't overwrite the zoomed in area. It's also using Craig's suggestion about using the SYS functions.
Thanks for the helpful explanation and links Craig. I wrote those SYS functions years ago. I hope you find them “decent” too<g>Anonymous
August 11, 2005
The comment has been removedAnonymous
August 12, 2005
In my last post Enable crop and zooming in on your digital photograph display form&nbsp; there is code...Anonymous
August 12, 2005
Thank you Craig for the explaination!
Calvin, if use ScrollBars = 3, then the croping doesn't work. Also when you single click on it, it goes back to the original image. I noticed this when tried to zoom futher.
Add the following code in the INIT event:
<pre>
this.ScrollBars = 3 this.AddObject("btn","commandbutton")
this.btn.Left = 500
this.btn.Width = 500
this.btn.Height= 500
this.btn.Visible = .t.
</pre>Anonymous
August 13, 2005
After having read a post on Calvin Hsia's weblog, I decided to try my hand at crAnonymous
August 19, 2005
Calvin,
I created a class based on your idea here for a rubberband selection. If you haven't seen it yet, you can at:
http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,de3b099f-bca6-471e-89bf-ae094b823780.aspx
Keep up the great Visual FoxPro related blog entries and ideas!Anonymous
February 16, 2007
Good job and great design!,Good job and great design!Anonymous
March 12, 2007
mmm.. nice design, I must say..Anonymous
March 16, 2007
Lo trovo piuttosto impressionante. Lavoro grande fatto..)Anonymous
March 18, 2007
Stupore! ho una sensibilit molto buona circa il vostro luogo!!!!Anonymous
April 07, 2007
9 su 10! Ottenerlo! Siete buoni!Anonymous
April 12, 2007
L'information interessante que vous avez! I'am allant revenir bientot.Anonymous
September 13, 2007
I received a customer question: I have looked all over the web and still searching, and found your blog.Anonymous
September 13, 2007
I received a customer question: I have looked all over the web and still searching, and found your blogAnonymous
December 22, 2007
<a href= http://wwwjcpennys.testlocseries1.info/ >www jc pennysAnonymous
December 22, 2007
<a href= http://wwwjcpennys.testlocseries1.info/ >www jc pennysAnonymous
August 21, 2008
Today’s digital cameras take pictures with much higher resolution than many computer screens. My CanonAnonymous
January 20, 2009
PingBack from http://www.hilpers-esp.com/486064-trabajo-con-graficos