ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/ns_dev/Python/NinoCode/Active_prgs/DisplayImage.py
Revision: 8
Committed: Sat May 5 04:21:19 2012 UTC (13 years, 10 months ago) by ninoborges
Content type: text/x-python
File size: 19936 byte(s)
Log Message:
Initial Import

File Contents

# User Rev Content
1 ninoborges 8 '''Image Display and Printing demo.
2    
3     Demonstrates a number of techniques for displaying and printing images using
4     the PythonWin MFC framework. This method of printing is suitable for
5     "automatic" printing, and so, uses the default printer settings.
6    
7     As this was ripped out of a larger app, I left some other stuff in as well:
8     *) The pixel value under the cursor is displayed in the title bar.
9     *) You can draw up to four circles on the image using the mouse.
10     *) After four circles are drawn, you can drag them to new locations.
11     *) You can delete a circle with the delete or backspace key.
12     *) Right click on the image to get an options menu (print only for now).
13    
14     Usage:
15     from the windows command line:
16     PythonWin.exe /app path/DisplayImage.py [-p -m mag] [imagePath]
17     where:
18     path: The directory containing this script
19     -p: If present, print the image and exit
20     -m mag: Only used if -p present, the magnification to print at,
21     defaults to 3
22     imagePath: The image to open and display
23     You may need to supply the PythonWin.exe path as well.
24     If you use the -p option, you must supply the imagePath as well
25     If no imagePath is given, an open file dialog is used to get the image.
26    
27     from the Python/PythonWin command prompt (or, within a script):
28     import DisplayImage
29     DisplayImage.displayImage() # Use file dialog to get and display an
30     # image
31     DisplayImage.displayImage(imgPath) # display given image
32     DisplayImage.printImage(imgPath, mag) # print image at mag.
33    
34     Requires: PIL (Python Imaging Library)
35     PythonWin (Build 125 or later)
36    
37     Written July 1999, Roger Burnham (rburnham@cri-inc.com)
38    
39     '''
40    
41     __version__ = '$Revision: 1.1 $'
42    
43     import sys, os
44     import string
45     import win32con, win32ui, win32api
46     from pywin.mfc import dialog, window
47     from pywin.framework import dlgappcore, app
48     import timer
49     import Image, ImageWin
50     from math import hypot, cos, sin, pi
51    
52    
53     _printAndExit = 0
54     _printMag = None
55     _defaultMag = 3
56     printing = 0
57     numDrawnCircles = 4
58     IDC_CROSS = 32515
59    
60    
61     cosTable = {}
62     sinTable = {}
63     degStep = 5
64     for deg in range(degStep, 360, degStep):
65     rad = deg*pi/180.0
66     cosTable[deg] = cos(rad)
67     sinTable[deg] = sin(rad)
68    
69    
70     APS_NEXT_COMMAND_VALUE = 36900
71     def nextCommandID():
72     global APS_NEXT_COMMAND_VALUE
73     id = APS_NEXT_COMMAND_VALUE
74     APS_NEXT_COMMAND_VALUE = APS_NEXT_COMMAND_VALUE + 1
75     return id
76    
77     APS_NEXT_CONTROL_VALUE = 16000
78     def nextControlID():
79     global APS_NEXT_CONTROL_VALUE
80     id = APS_NEXT_CONTROL_VALUE
81     APS_NEXT_CONTROL_VALUE = APS_NEXT_CONTROL_VALUE + 1
82     return id
83    
84    
85     color = {'Black' : ( 0<<0) + ( 0<<8) + ( 0<<16),
86     'Red' : (255<<0) + ( 0<<8) + ( 0<<16),
87     'Green' : ( 0<<0) + (230<<8) + ( 0<<16),
88     'Blue' : ( 0<<0) + ( 0<<8) + (255<<16),
89     'Cyan' : ( 0<<0) + (255<<8) + (255<<16),
90     'Magenta' : (255<<0) + ( 0<<8) + (255<<16),
91     'Yellow' : (255<<0) + (255<<8) + ( 0<<16),
92     'White' : (255<<0) + (255<<8) + (255<<16),
93     'Tan' : (203<<0) + (145<<8) + ( 86<<16),
94     'Sand' : (248<<0) + (242<<8) + (131<<16),
95     'Pink' : (255<<0) + (106<<8) + (167<<16),
96     'Red-Orange' : (255<<0) + ( 69<<8) + ( 0<<16),
97     'Orange' : (255<<0) + (165<<8) + ( 0<<16),
98     'Crimson' : (210<<0) + ( 11<<8) + ( 16<<16),
99     'Olive' : (105<<0) + (139<<8) + ( 34<<16),
100     'Light Green' : ( 45<<0) + (255<<8) + ( 45<<16),
101     'Dark Green' : ( 0<<0) + (110<<8) + ( 0<<16),
102     }
103    
104    
105     pen = {}
106     brush = {}
107     for key in color.keys():
108     pen[key] = win32ui.CreatePen(win32con.PS_SOLID, 0, color[key])
109     brush[key] = win32ui.CreateBrush(win32con.BS_SOLID, color[key], 0)
110    
111    
112     def rgb(col):
113     v = color[col]
114     return (v>>0)&0xff, (v>>8)&0xff, (v>>16)&0xff
115    
116    
117     def imagetemplate(img):
118     style = (win32con.DS_MODALFRAME |
119     win32con.WS_POPUP |
120     win32con.WS_VISIBLE |
121     win32con.WS_CAPTION |
122     win32con.WS_SYSMENU)
123     try:
124     direc, file = os.path.split(img.filename)
125     name, ext = os.path.splitext(file)
126     except:
127     name = 'Image'
128     baseUnitX = 6
129     baseUnitY = 13
130     minW = len(' %s: (999,999) = 999 )' % name)*baseUnitX
131     w = (max(img.size[0], minW)*4)/baseUnitX + 1
132     h = (img.size[1]*8)/baseUnitY + 1
133     extendedStyle = None
134     font = None
135     menuID = None
136     windowClass = None
137     return [[name, (0, 0, w, h), style,
138     extendedStyle, font, menuID, windowClass,],]
139    
140    
141     class ImgCtl(window.Wnd):
142    
143     def __init__ (self, img):
144     window.Wnd.__init__(self, win32ui.CreateWnd())
145     if img.mode not in ('RGB', 'L'):
146     pilMode = 'RGB'
147     else:
148     pilMode = img.mode
149     self.pilDisplay = ImageWin.Dib(pilMode, img.size)
150     self.pilDisplay.paste(img)
151    
152     def OnDestroy(self, msg):
153     window.Wnd.OnDestroy(self, msg)
154     del self.pilDisplay.image
155     del self.pilDisplay
156    
157     def OnPaint(self):
158     dc, paintStruct = self.BeginPaint()
159     self.pilDisplay.expose(dc.GetHandleOutput())
160     self.EndPaint(paintStruct)
161    
162    
163     class ImageDisplay(dialog.Dialog):
164    
165     cursor = None
166     menuID = None
167     menuList = None
168    
169     def __init__(self, img, pos, drawable):
170     self.app = win32ui.GetApp()
171     self.img = img
172     self.pos = pos
173     self.circleList = []
174     self.drawable = drawable
175     self.size = img.size
176     self.mouseDown = 0
177     self.drawing = 0
178     self.moving = None
179     self.mousexy = (0,0)
180     dialog.Dialog.__init__(self, imagetemplate(img))
181     if ImageDisplay.cursor is None:
182     ImageDisplay.cursor = self.app.LoadStandardCursor(IDC_CROSS)
183     if ImageDisplay.menuID is None:
184     ImageDisplay.menuList = ['Avaliable Image Options',]
185     ImageDisplay.menuList.append('Print')
186     ImageDisplay.menuID = []
187     for i in range(len(self.menuList)):
188     ImageDisplay.menuID.append(nextCommandID())
189    
190     def PreDoModal(self):
191     pass
192    
193     def OnInitDialog(self):
194     rc = dialog.Dialog.OnInitDialog(self)
195     self.SetWindowPos(win32con.HWND_TOP,
196     tuple(list(self.pos) + [0, 0]),
197     win32con.SWP_NOSIZE)
198     self.imgCtl = ImgCtl(self.img)
199     w = self.size[0]
200     h = self.size[1]
201     self.imgCtl.CreateWindow (None, self.img.filename,
202     (win32con.WS_CHILD|
203     win32con.WS_VISIBLE),
204     (0, 0, w, h),
205     self,
206     nextControlID())
207     self.title = self.GetWindowText()
208     self.imgCtl.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE)
209     self.imgCtl.HookMessage(self.OnSetCursor, win32con.WM_SETCURSOR)
210     self.imgCtl.HookMessage(self.OnLMouseDown, win32con.WM_LBUTTONDOWN)
211     self.imgCtl.HookMessage(self.OnLMouseUp, win32con.WM_LBUTTONUP)
212     self.imgCtl.HookMessage(self.HandleKeys, win32con.WM_KEYUP)
213     self.imgCtl.HookMessage(self.OnRMouseUp, win32con.WM_RBUTTONUP)
214     if _printAndExit:
215     self.timer = timer.set_timer(100, self._startPrint)
216     return rc
217    
218     def _startPrint(self, tid, sysTime):
219     global printing
220     timer.kill_timer(self.timer)
221     printing = 1
222     self.OnDraw(self.GetDC())
223    
224     def OnOK(self):
225     pass
226    
227     def OnClose(self, *msg):
228     try:
229     self.imgCtl.DestroyWindow()
230     self._obj_.OnClose()
231     except:
232     pass
233    
234     def OnDestroy(self, msg):
235     try:
236     dialog.Dialog.OnDestroy(self, msg)
237     del self.circleList
238     del self.img
239     del self.title
240     del self.imgCtl
241     except:
242     pass
243    
244     def OnSetCursor(self, *arg):
245     win32api.SetCursor(ImageDisplay.cursor)
246    
247     def OnDraw(self, dc, fill=None):
248     global printing
249     if printing:
250     if _printAndExit:
251     mag = _printMag or _defaultMag
252     else:
253     newMag = GetSimpleInput(
254     'Print Setup',
255     'Enter an image magnification:',
256     `_defaultMag`)
257     try:
258     mag = string.atoi(newMag)
259     except:
260     mag = _defaultMag
261    
262     dc.CreatePrinterDC()
263     dc.StartDoc(self.img.filename)
264     dc.StartPage()
265     dc.SetMapMode(win32con.MM_ANISOTROPIC)
266     dc.SetWindowOrg((0, 0))
267     dc.SetWindowExt((1, 1))
268     dc.SetViewportOrg((0, 0))
269     dc.SetViewportExt((mag, mag))
270    
271     metrics = dc.GetTextMetrics()
272     cxChar = metrics['tmAveCharWidth']
273     cyChar = metrics['tmHeight']
274     left, top, right, bottom = (0, 0,
275     self.img.size[0],
276     self.img.size[1])
277    
278     dc.TextOut(0, 2*cyChar, self.img.filename)
279     top = top + (7*cyChar)/2
280     dc.MoveTo(left, top)
281     dc.LineTo(right, top)
282     top = top + cyChar
283     dc.SetWindowOrg((0, -top))
284    
285     self.imgCtl.pilDisplay.expose(dc.GetHandleOutput())
286    
287     height = self.img.size[1]
288     dc.SetTextColor(color['Black'])
289     dc.SetTextAlign(win32con.TA_LEFT|win32con.TA_BOTTOM)
290    
291     dc.SetWindowOrg((0, -(top+height+cyChar)))
292     dc.MoveTo(left, 0)
293     dc.LineTo(right, 0)
294    
295     x = 0
296     y = (3*cyChar)/2
297    
298     dc.SetWindowOrg((0, -top))
299    
300     oldPen = dc.SelectObject(pen['Cyan'])
301     oldBrush = dc.SelectObject(brush['Cyan'])
302     dc.SetBkMode(win32con.TRANSPARENT)
303     if not self.mouseDown:
304     dc.SetTextAlign(win32con.TA_CENTER|win32con.TA_BOTTOM)
305     w,h = dc.GetTextExtent('4')
306    
307     i = 0
308     for circle in self.circleList:
309     if not self.mouseDown:
310     if self.regionSelected(self.mousexy, circle) or fill == i:
311     if fill:
312     dc.SelectObject(pen['Cyan'])
313     else:
314     dc.SelectObject(pen['Blue'])
315     dc.SelectObject(brush['Blue'])
316     dc.SetTextColor(color['Blue'])
317     else:
318     dc.SelectObject(pen['Cyan'])
319     dc.SelectObject(brush['Cyan'])
320     dc.SetTextColor(color['Cyan'])
321     if fill == i:
322     dc.BeginPath()
323     if fill is None or fill == i:
324     x0, y0, r = circle
325     dc.MoveTo((x0+r, y0))
326     for deg in range(degStep, 360, degStep):
327     x = x0 + int(round(r*cosTable[deg]))
328     y = y0 + int(round(r*sinTable[deg]))
329     dc.LineTo((x,y))
330     dc.LineTo((x0+r, y0))
331     if fill == i:
332     dc.EndPath()
333     dc.StrokeAndFillPath()
334     i = i + 1
335     if not self.mouseDown and fill is None:
336     dc.TextOut(x0+r+w, y0+h/2, `i`)
337     dc.SelectObject(oldBrush)
338     dc.SelectObject(oldPen)
339    
340     if printing:
341     dc.EndPage()
342     dc.EndDoc()
343     printing = 0
344     if _printAndExit:
345     win32api.PostQuitMessage(1)
346    
347     def OnLMouseDown(self, arg):
348     if not self.drawable:
349     return
350     x,y = xy = self.ScreenToClient(arg[5])
351     if (x<0 or x>=self.size[0] or
352     y<0 or y>=self.size[1]):
353     return
354     self.imgCtl.SetCapture()
355     self.mouseDown = 1
356     self.moving = None
357     if len(self.circleList) < numDrawnCircles:
358     self.circle = [xy[0], xy[1], 0]
359     self.circleList.append(self.circle)
360     self.drawing = 1
361     else:
362     moveNum = None
363     for i in range(len(self.circleList)):
364     if self.regionSelected(self.mousexy, self.circleList[i]):
365     moveNum = i
366     break
367     self.moving = moveNum
368     if self.moving is not None:
369     xy = tuple(self.circleList[self.moving][:2])
370     win32api.SetCursorPos(self.ClientToScreen(xy))
371     self.moveCnt = 4
372     self.xy = xy
373     self.startxy = xy
374     self.mousexy = xy
375    
376     def OnMouseMove(self, arg):
377     xy = self.ScreenToClient(arg[5])
378     self.mousexy = xy
379     caption = self.getCaption(xy)
380     if caption is not None:
381     self.SetWindowText(caption)
382     win32api.SetCursor(ImageDisplay.cursor)
383     if self.mouseDown and self.imgCtl.MouseCaptured():
384     if self.drawing:
385     r = hypot(self.startxy[0]-xy[0], self.startxy[1]-xy[1])
386     self.circle[2] = r
387     self.xy = xy
388     elif self.moving is not None:
389     x0, y0, r = self.circleList[self.moving]
390     x0 = x0 + (xy[0] - self.startxy[0])
391     y0 = y0 + (xy[1] - self.startxy[1])
392     minD = 4
393     w = self.size[0] - minD
394     h = self.size[1] - minD
395     if (
396     (x0-r > minD and y0 > minD and
397     x0-r < w and y0 < h)
398     or
399     (x0 > minD and y0+r > minD and
400     x0 < w and y0+r < h)
401     or
402     (x0+r > minD and y0 > minD and
403     x0+r < w and y0 < h)
404     or
405     (x0 > minD and y0-r > minD and
406     x0 < w and y0-r < h)
407     ):
408     self.circleList[self.moving][0] = x0
409     self.circleList[self.moving][1] = y0
410     self.startxy = xy
411     if self.drawing or self.moving is not None:
412     self.moveCnt = self.moveCnt - 1
413     if self.moveCnt == 0:
414     self.moveCnt = 2
415     self.InvalidateRect()
416     self.imgCtl.InvalidateRect()
417     self.OnDraw(self.GetDC())
418    
419     def OnLMouseUp(self, arg):
420     if not self.drawable:
421     return
422     if self.imgCtl.MouseCaptured():
423     self.imgCtl.ReleaseCapture()
424     self.drawing = 0
425     self.moving = None
426     self.mouseDown = 0
427     self.mousexy = self.ScreenToClient(arg[5])
428     self.InvalidateRect()
429     self.imgCtl.InvalidateRect()
430     self.OnDraw(self.GetDC())
431    
432     def OnRMouseUp(self, msg):
433     hWnd = msg[0]
434     menu = win32ui.CreatePopupMenu()
435    
436     titleFlags = win32con.MF_STRING|win32con.MF_DISABLED
437     itemFlags = win32con.MF_STRING|win32con.MF_ENABLED
438     menuFlags = (win32con.TPM_LEFTALIGN|win32con.TPM_LEFTBUTTON|
439     win32con.TPM_RETURNCMD|win32con.TPM_NONOTIFY)
440    
441     menu.AppendMenu(titleFlags, self.menuID[0], self.menuList[0])
442     menu.AppendMenu(win32con.MF_SEPARATOR)
443     for i in range(1, len(self.menuList)):
444     menu.AppendMenu(itemFlags, self.menuID[i],
445     self.menuList[i])
446    
447     try:
448     rc = menu.TrackPopupMenu(msg[5], menuFlags, self)
449     except:
450     return
451    
452     if rc == self.menuID[1]:
453     global printing
454     printing = 1
455     self.OnDraw(self.GetDC())
456    
457     def HandleKeys(self, msg):
458     if not self.drawable:
459     return
460     if self.mouseDown:
461     return
462     key = msg[2]
463     if (key == win32con.VK_DELETE or
464     key == win32con.VK_BACK):
465     found = 0
466     i = 0
467     for circle in self.circleList:
468     if self.regionSelected(self.mousexy, circle):
469     found = 1
470     break
471     i = i + 1
472     if found:
473     del self.circleList[i]
474     self.InvalidateRect()
475     self.imgCtl.InvalidateRect()
476     self.timer = timer.set_timer(100, self.refresh)
477    
478     def refresh(self, *args):
479     timer.kill_timer(self.timer)
480     self.OnDraw(self.GetDC())
481    
482     def getCaption(self, xy):
483     try:
484     return '%s: (%3d,%3d) = %s' % (self.title, xy[0], xy[1],
485     `self.img.getpixel(xy)`)
486     except:
487     return None
488    
489     def regionSelected(self, pnt, region):
490     return self.drawable and (hypot(pnt[0]-region[0],
491     pnt[1]-region[1])
492     < (region[2]+4))
493    
494    
495     def GetSimpleInput(title, prompt, defValue=''):
496     dlg = SimpleInput(title, prompt, defValue)
497     if dlg.DoModal() <> win32con.IDOK:
498     ret = dlg.defValue
499     else:
500     ret = dlg['result']
501     return ret
502    
503    
504     class SimpleInput(dialog.Dialog):
505    
506     def __init__(self, title, prompt, defValue):
507     self.title = title
508     self.defValue = defValue
509     dialog.Dialog.__init__(self, win32ui.IDD_SIMPLE_INPUT)
510     self.AddDDX(win32ui.IDC_EDIT1, 'result')
511     self.AddDDX(win32ui.IDC_PROMPT1, 'prompt')
512     self._obj_.data['result'] = defValue
513     self._obj_.data['prompt'] = prompt
514    
515     def OnInitDialog(self):
516     self.SetWindowText(self.title)
517     self._obj_.UpdateData(0)
518     return dialog.Dialog.OnInitDialog(self)
519    
520    
521     class PrintDialogApp(dlgappcore.DialogApp):
522     def __init__(self):
523     if len(sys.argv) > 1:
524     import getopt
525     opts, args = getopt.getopt(sys.argv[1:], 'pm:')
526     if len(args):
527     img = args[0]
528     for o, v in opts:
529     if o == '-p':
530     global _printAndExit
531     _printAndExit = 1
532     elif o == '-m':
533     global _printMag
534     _printMag = string.atoi(v)
535     else:
536     flags = (~win32con.OFN_ALLOWMULTISELECT &
537     (win32con.OFN_FILEMUSTEXIST|win32con.OFN_EXPLORER))
538     dlg = win32ui.CreateFileDialog(1, None, None, flags,
539     'Image File (*.*)|*.*||')
540     dlg.SetOFNTitle('Image to Display')
541     if dlg.DoModal() == win32con.IDOK:
542     img = dlg.GetPathNames()[0]
543     else:
544     return
545     dlgappcore.DialogApp.__init__(self)
546     self.image = Image.open(img)
547    
548     def CreateDialog(self):
549     return ImageDisplay(self.image, (100,100), 1)
550    
551    
552     def displayImage(img=None):
553     runIt(script=__file__, img=img)
554    
555    
556     def printImage(img, mag):
557     global _printAndExit
558     runIt(script=__file__, img=img, opts='-p -m %d' % mag)
559    
560    
561     def runIt(script=None, img=None, opts=None):
562     parent = win32ui.GetMainFrame().GetSafeHwnd()
563     if script is None:
564     args = '/app "%s"' % sys.argv[0]
565     else:
566     args = '/app "%s"' % script
567     if opts is not None:
568     args = args + ' %s' % opts
569     if img is not None:
570     args = args + ' "%s"' % img
571     win32api.ShellExecute(parent, None, 'pythonwin.exe', args, None, 1)
572    
573    
574     app.AppBuilder = PrintDialogApp
575    
576    
577     if __name__== '__main__':
578     runIt()
579