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

# Content
1 '''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