#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, tempfile, sys, traceback
import wx
from library.ftp import read_conf
import wx_util
#Cursor direction
handle_LEFT = 1
handle_RIGHT = 2
handle_TOP = 4
handle_BOTTOM = 8
def create(parent, img2open):
return Img_view(parent, img2open)
class Img_view(wx.Frame):
def __init__(self, parent, img2open = [], close = 1, text4print = '',
paths = '', opt_cls='', funct4save='', only4test=0, modify=0):
super(Img_view, self).__init__(parent, -1, 'FaxView', style=wx.WANTS_CHARS|wx.DEFAULT_FRAME_STYLE)
self._p = wx.Panel(self, style=wx.WANTS_CHARS)
#self.SetBackgroundColour(wx.Colour(225, 225, 225))
self.opt_cls = opt_cls
self.paths = paths
self.text4print = text4print
self.funct4save = funct4save
#Control paths
if not paths:
self.pref = read_conf.pref('hylapex')
self.my_path = self.pref.get_my_path()
self.paths = None
else:
self.my_path = paths.my_path
self.paths = paths
self.my_path_imgs = os.path.join(self.my_path, 'imgs')
self.close = close
self.modify = modify
#Go with panel, buttons and sizer
self._sizer()
#I put here this code because I must resize the frame after set the sizer
toolPos = wx.Size(0,0)
if paths:
#Image view position
if not self.opt_cls.has_option('imgview_sp'):
self.CenterOnParent()
else:
SizePos = self.opt_cls.get('imgview_sp')
size, pos = SizePos.split(';')
sizeX, sizeY = size.split(',')
posX, posY = pos.split(',')
self.SetSize(wx.Size(int(sizeX), int(sizeY)))
self.SetPosition(wx.Point(int(posX), int(posY)))
#Tool position
if self.modify and self.opt_cls.has_option('imgview_tool_p'):
pos = self.opt_cls.get('imgview_tool_p')
posX, posY = pos.split(',')
toolPos = wx.Point(int(posX), int(posY))
#Control type
if type(img2open) != type( list() ):
img2open = [img2open]
self.img2open = img2open
if not only4test:
self.zoom = opt_cls.getint('cho_zoom')
if not self.zoom:
self.zoom = 40
self.font4print = opt_cls.get('txt_fontsize')
else:
self.zoom = 100
self.font4print = 10
self.modify = 1
self.SetSize(wx.Size(500,500))
class _ren:
def get(self, *args): return ""
def set(self, *args): return ""
def __class__(self, *args): return self.get()
def funct4save(files):
print "I'll try to load the just created image", files[0]
os.system("kview %s" % files[0])
self.opt_cls = _ren()
self.ren = _ren()
self.funct4save = funct4save
#i18n
if paths:
self.ren = wx_util.rename_ctrls(self, 'img_view', paths.my_path, \
lang = paths.language)
self.ren.rename()
elif not self.ren:
self.ren = None
#Modify vars
self._lines4page = dict()
self._text4page = dict()
self._img4page = dict()
self._list4undo = list()
self._moving_text = -1
self._moving_img = -1
self._dragging_text = 0
self._drawing = 0
self._dragging_img = 0
# Update variables need for draw
for i in xrange(len(self.img2open)+1):
self._lines4page[i] = list()
self._text4page[i] = list()
self._img4page[i] = list()
self.images = None
#Control the images
for i in self.img2open:
if os.path.exists( str(i) ): continue
self.img2open = list()
wx.MessageBox('Image %s not found. Please close and reopen the program' % str(i) ,
'Error', wx.ICON_ERROR)
return
#Current work image list
self.images = internalImage(self.img2open)
h, w = self.images.GetHeight(), \
self.images.GetWidth()
self.drawPanelInitSize = wx.Size(w, h)
#Move the image
self.grip = False
self.grip_pos = wx.Point(0,0)
#Polulate the wxchoice page
num_pages = len(img2open)
for i in xrange(1, len(img2open) + 1):
self.choPage.Append("%s / %s" % (i, num_pages))
#and zoom
self.zoomList = list()
for i in xrange(20, 150, 10):
self.zoomList.append(i)
self.choZoom.Append('%s' % i)
#and rotation
self.images.setRotationList( (0, 90, 180, 270) )
for i in self.images.getRotationList():
self.choRot.Append(str(i))
self.choPage.SetSelection(0)
self.choRot.SetStringSelection('0')
self.choZoom.SetStringSelection('%s' % self.zoom)
#Enable / disable widgets
self.btprev.Enable(False)
if len(img2open) == 1:
for widg in (self.btnext, self.btprev, \
self.choPage):
widg.Enable(False)
self._ResizePanel()
if self.modify:
import tools_view
self.tools = tools_view.Tools(self, paths, pos=toolPos)
self.CtrlCursor()
self.tools.Show()
self._dcDrawLines = None
def doPaint(self, event):
""" Respond to the paint method
"""
if self.images:
self.images.loadImage()
else:
event.Skip()
return
self.SetTitle( 'FaxView -- %s' % self.images.getImageName() )
dc = wx.PaintDC(self.drawPanel)
self.drawPanel.PrepareDC(dc)
dc.SetUserScale(self._getCurrentZoom(), self._getCurrentZoom())
self._privateDraw(dc)
def doPrint(self, event):
""" Go with printer
"""
printData = wx.PrintData()
printData.SetPaperId(wx.PAPER_A4)
#Black and white
printData.SetColour(0)
pdlgdata = wx.PrintDialogData(printData)
printer = wx.Printer(pdlgdata)
printout = myPrintOut(self.images, text = self.text4print,
font4print = self.font4print)
printer.Print(self, printout)
def doClose(self, event=None):
""" Perform close operation
"""
modified = 0
for val in self._lines4page:
if self._lines4page[val]:
modified = 1
break
for val in self._text4page:
if modified: break
if self._text4page[val]:
modified = 1
for val in self._img4page:
if self._img4page[val]:
modified = 1
break
if modified:
if self.ren:
title = self.ren.get('_save')
quest = self.ren.get('_save_modify')
else:
title = self.ren.get('Save?')
quest = self.ren.get('I found some modify. Do you want to save?')
dlg = wx.MessageDialog(self, quest, title, wx.ICON_QUESTION | wx.YES_NO)
if dlg.ShowModal() == wx.ID_NO:
modified = 0
dlg.Destroy()
if self.funct4save and modified:
self.funct4save( self.savePanelToBmp() )
#Save img_view size and position
sx, sy = self.GetSize()
px, py = self.GetPosition()
size = "%s,%s" % (sx, sy)
pos = "%s,%s" % (px, py)
if not self.IsIconized():
self.opt_cls.set('imgview_sp', "%s;%s" % (size, pos) )
#Save tool_view position
if self.modify:
pTx, pTy = self.tools.GetPosition()
self.opt_cls.set('imgview_tool_p', "%s,%s" % (pTx, pTy) )
self.Destroy()
print 'close imgview'
def doNext(self, event):
""" Display Next page
"""
if len(self.img2open)-1 == self.images.getCurrentPage(): return
self.images.addToCurrentPage( 1 )
self._btCtrl()
self.choPage.SetSelection(self.images.getCurrentPage())
self._setRotateChoice()
self.drawPanel.Refresh()
def doPreview(self, event):
""" Display the preview page
"""
if self.images.getCurrentPage() == 0: return
self.images.addToCurrentPage( -1 )
self._btCtrl()
self.choPage.SetSelection(self.images.getCurrentPage())
self._setRotateChoice()
self.drawPanel.Refresh()
def doRotDx(self, event):
"""
"""
self._rotate(1)
def doRotSx(self, event):
"""
"""
self._rotate(0)
def doZoomIn(self, event):
"""
"""
self._adjustZoom('n')
def doZoomOut(self, event):
"""
"""
self._adjustZoom('p')
def doZoomChoice(self, event):
""" Respond to the zoom choice
"""
self.zoom = int(event.GetString())
self._ResizePanel()
def doRotChoice(self, event):
""" Do rotation choice
"""
self._intRotChoice( int(event.GetString()) )
def doPageChoice(self, event):
""" Choose page
"""
self.images.setCurrentPage( int(event.GetString().split("/")[0]) -1 )
self._btCtrl()
self.drawPanel.Refresh()
def doMouseEvt(self, event):
""" Do the mouse events
"""
x, y = self.ConvertEventCoords(event)
x, y = int(x), int(y)
if self.modify:
side = None
data = self._getSideOverBorder(x, y)
if data: side = data[1]
self.CtrlCursor(side)
if not (event.LeftDown() or event.Dragging() or event.LeftUp()):
event.Skip()
# Ignore mouse movement without click/drag.
return
#Pay attention to the pen moves
if self.modify and self.tools.bt_pen.GetValue():
self.CtrlLine(event)
elif self.modify and self.tools.bt_text.GetValue():
self.CtrlText(event)
elif self.modify and self.tools.bt_img.GetValue():
self.CtrlImage(event)
else:
self.CtrlMove(event)
def doKeyEvt(self, evt):
""" Respond to the the key (from F1 to F4)
"""
kc = evt.GetKeyCode()
lst_k = [wx.WXK_F1, wx.WXK_F2, wx.WXK_F3, wx.WXK_F4]
if not kc in lst_k:
evt.Skip()
return
d_img = {}
for num in xrange(5):
#load the 4 keys from the conf
prev_name = "preview_img_sc_f%s" % num
if self.opt_cls.has_option(prev_name):
d_img[num] = self.opt_cls.get(prev_name)
else:
d_img[num] = None
img_path = d_img[lst_k.index(kc) + 1]
if not img_path:
#no image found. Return
evt.Skip()
return
self.tools.SetButton(self.tools.bt_img, 1)
self._add_image(10, 10, img_path)
def doMouseWheel(self, event):
""" Scroll the frame, not move the wxChoice
"""
if event.GetWheelRotation() < 0:
self.drawPanel.ScrollLines(2)
else:
self.drawPanel.ScrollLines(-2)
def _ResizePanel(self, su=20):
""" Work with zoom, size is used only first time
"""
w, h = self.images.GetWidth(), self.images.GetHeight()
w = w * self._getCurrentZoom()
h = h * self._getCurrentZoom()
self.drawPanel.SetScrollbars(su, su, w/su, h/su)
self.panelSizer.Layout()
self.drawPanel.Refresh()
def _adjustZoom(self, side, adjCho=1):
pos = self.zoomList.index(self.zoom)
if side == 'p':
#I cannot do preview zoom on the first zoom
if not pos == 0:
self.zoom = self.zoomList[pos -1]
else:
#I cannot do preview zoom on the first zoom
if pos != len(self.zoomList)-1:
self.zoom = self.zoomList[pos +1]
if adjCho:
self.choZoom.SetStringSelection('%i' % self.zoom)
self._ResizePanel()
def _rotate(self, side):
""" Rotate the image
"""
if side:
self.images.rotateDx()
else:
self.images.rotateSx()
#Update the choice
self._setRotateChoice()
self._ResizePanel()
self.drawPanel.Refresh()
def _btCtrl(self):
""" Control the button enable/disable state
"""
cp = self.images.getCurrentPage()
if cp == 0:
self.btnext.Enable(True)
self.btprev.Enable(False)
elif cp == len(self.img2open) -1:
self.btnext.Enable(False)
self.btprev.Enable(True)
else:
self.btnext.Enable(True)
self.btprev.Enable(True)
def _SaveImages(self, path):
""" Help method for save the images
"""
dlg = wx.MessageDialog(self, self.parent.ren.get('_save_modify'),
self.parent.ren.get('_save'), wx.ICON_QUESTION | wx.YES_NO)
ret = dlg.ShowModal() == wx.ID_YES
dlg.Destroy()
if ret:
files = list()
for num, page in enumerate(self.img2open):
self.choose_page(num+1, 1)
fo = tempfile.mkstemp(dir=path, suffix = '%s.tiff' % str(num))[1]
page.SetOption(wx.IMAGE_OPTION_COMPRESSION, "2")
page.SaveFile(fo, wx.BITMAP_TYPE_TIF)
files.append(fo)
return files
else:
return ''
def CtrlCursor(self, side=None):
""" Control and set the current cursor
"""
if self._dragging_img:
return
if side:
if (side & handle_RIGHT) and (side & handle_BOTTOM): cur = wx.CURSOR_SIZENWSE
elif (side & handle_RIGHT) and (side & handle_TOP): cur = wx.CURSOR_SIZENESW
elif (side & handle_LEFT) and (side & handle_BOTTOM): cur = wx.CURSOR_SIZENESW
elif (side & handle_LEFT) and (side & handle_TOP): cur = wx.CURSOR_SIZENWSE
elif side & handle_RIGHT: cur = wx.CURSOR_SIZEWE
elif side & handle_LEFT: cur = wx.CURSOR_SIZEWE
elif side & handle_BOTTOM: cur = wx.CURSOR_SIZENS
elif side & handle_TOP: cur = wx.CURSOR_SIZENS
else:
return
else:
if self.tools.bt_pen.GetValue(): cur = wx.CURSOR_PENCIL
elif self.tools.bt_text.GetValue(): cur = wx.CURSOR_CROSS
elif self.tools.bt_img.GetValue(): cur = wx.CURSOR_DEFAULT
else: cur = wx.CURSOR_HAND
self.drawPanel.SetCursor(wx.StockCursor(cur))
def CtrlMove(self, event):
""" Move the image over mouse
"""
MN = 20
if event.LeftDown():
self.grip = True
mx, my = event.GetPosition()
mx, my = mx/MN, my/MN
self.grip_pos = mx, my
self.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
elif event.Dragging():
x, y = self.ScreenToClient(wx.GetMousePosition())
vx, vy = self.drawPanel.GetViewStart()
if self.grip:
ox, oy = self.grip_pos
mx, my = event.GetPosition()
mx, my = mx/MN, my/MN
sx, sy = vx+(ox-mx), vy+(oy-my)
self.drawPanel.Scroll(sx, sy)
self.grip_pos = mx, my
elif event.LeftUp() and self.grip:
self.SetCursor(wx.NullCursor)
self.grip = False
else:
event.Skip()
def CtrlLine(self, event):
if event.LeftDown():
self.SetXY(event)
self.curLine = []
self._drawing = True
elif event.Dragging() and self._drawing:
try:
line_w = self.tools.txt_line_w.GetValue()
lw = int(line_w)
except ValueError:
event.Skip()
dlg = wx.MessageDialog(self, '%s %s %s' %
(self.ren.get('value', 1), line_w, self.ren.get('invalid', 1)),
self.ren.get('error', 1), wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
return
x, y = self.ConvertEventCoords(event)
coords = (self.x, self.y) + (x, y)
self._drawLineTime(coords,lw = lw, col=self.tools.CurColor)
data = (coords, lw, self.tools.CurColor)
self.curLine.append(data)
self.SetXY(event)
elif event.LeftUp() and self._drawing:
self._lines4page[self.images.getCurrentPage()].append(self.curLine)
self.curLine = []
self._drawing = False
#self.drawPanel.Refresh()
self._list4undo.append('l')
self._drawLineTime(end=1)
def CtrlText(self, event):
x, y = self.ConvertEventCoords(event)
text_data = self._getTextAt(x,y)
if text_data and self._moving_text == -1:
tmp_data, self._moving_text = text_data
text, xT, yT, font = tmp_data
if event.LeftDown() and self._moving_text == -1:
""" New text
"""
dlg = wx.TextEntryDialog(self, self.ren.get('_insert_text'),
self.ren.get('text', 1), '')
text = ''
if dlg.ShowModal() == wx.ID_OK:
text = dlg.GetValue()
dlg.Destroy()
if not text: return
data = (text, x, y, self.tools._GetFont(), self.tools.CurColor)
self._text4page[self.images.getCurrentPage()].append(data)
self._list4undo.append('t')
self.drawPanel.Refresh()
elif event.LeftDown() and self._moving_text != -1:
#Calculate the relative position
xT, yT = self._text4page[self.images.getCurrentPage()][self._moving_text][1:3]
self._textDx = int(x - xT)
self._textDy = int(y - yT)
self._oldObjPos = wx.Point(x,y)
self._drawObjRect(x, y)
elif event.LeftUp() and self._moving_text != -1 and not self._dragging_text:
""" Modify text
"""
text, xT, yT = self._text4page[self.images.getCurrentPage()][self._moving_text][:3]
dlg = wx.TextEntryDialog(self, self.ren.get('_insert_text'),
self.ren.get('text', 1), text)
if dlg.ShowModal() == wx.ID_OK:
text = dlg.GetValue()
dlg.Destroy()
else:
dlg.Destroy()
return
self._text4page[self.images.getCurrentPage()].pop(self._moving_text)
dlg.Destroy()
if not text: return
data = (text, xT, yT , self.tools._GetFont(), self.tools.CurColor)
self._text4page[self.images.getCurrentPage()].append(data)
self._moving_text = -1
self.drawPanel.Refresh()
elif event.LeftUp() and self._moving_text != -1 and self._dragging_text:
"""We have finished to drag
"""
text, xT, yT, font = \
self._text4page[self.images.getCurrentPage()].pop(self._moving_text)[:4]
data = (text, x - self._textDx, y -self._textDy , self.tools._GetFont(), self.tools.CurColor)
self._text4page[self.images.getCurrentPage()].append(data)
self._dragging_text = 0
self._moving_text = -1
self.drawPanel.Refresh()
elif event.Dragging() and self._moving_text != -1:
self._dragging_text = 1
oldX, oldY = self._oldObjPos
if (x != oldX) or ( y != oldY ):
self._drawObjRect(oldX, oldY)
self._oldObjPos = wx.Point(x,y)
self._drawObjRect(x, y)
def CtrlImage(self, event):
"""
"""
x,y = map(int, self.ConvertEventCoords(event))
data = self._getImageAt(x,y, not event.Dragging())
if self._moving_img == -1:
#add a new image
self._add_image(x, y)
elif event.LeftDown():
"""Start to move. Calculate the relative position
"""
data = self._getSideOverBorder(x,y)
if data:
self._resizing = data
else:
self._resizing = None
if not self._img4page:
return
xT, yT = self._img4page[self.images.getCurrentPage()][self._moving_img][1:3]
self._textDx = int(x - xT)
self._textDy = int(y - yT)
self._oldObjPos = wx.Point(x,y)
self._drawObjRect(x, y)
elif event.LeftUp():
"""We have finished to drag or on click over an image
"""
if self._dragging_img:
bmp, xTPos, yTPos, xTsize, yTsize = \
self._img4page[self.images.getCurrentPage()].pop(self._moving_img)
oldX, oldY = self._oldObjPos
if self._resizing:
newW, newH = xTsize, yTsize
side_res = self._resizing[1]
if side_res & handle_BOTTOM:
newH = yTsize + (y - oldY)
if side_res & handle_TOP:
newH = yTsize + (oldY - y)
yTPos = y
if side_res & handle_RIGHT:
newW = xTsize + (x - oldX)
if side_res & handle_LEFT:
newW = xTsize + (oldX - x)
xTPos = x
img = wx.ImageFromBitmap(bmp)
img.Rescale(newW, newH)
data = (wx.BitmapFromImage(img), xTPos, yTPos, newW, newH)
else:
data = (bmp, x -self._textDx, y -self._textDy, xTsize, yTsize)
self._img4page[self.images.getCurrentPage()].append(data)
self._dragging_img = 0
self._moving_img = -1
self.drawPanel.Refresh()
#wx.FutureCall(20, self._drawObjRect, x, y)
elif event.Dragging():
self._dragging_img = 1
if self._resizing:
return
oldX, oldY = self._oldObjPos
if (x != oldX) or ( y != oldY ):
self._drawObjRect(oldX, oldY)
self._oldObjPos = wx.Point(x,y)
self._drawObjRect(x, y)
def GoUndo(self):
""" Process the undo command
"""
if not self._list4undo: return
type = self._list4undo.pop()
if type == 'l':
self._lines4page[self.images.getCurrentPage()].pop()
elif type == 't':
self._text4page[self.images.getCurrentPage()].pop()
elif type == 'i':
self._img4page[self.images.getCurrentPage()].pop()
self.drawPanel.Refresh()
def savePanelToBmp(self):
""" Save the current panel to a bitmap
"""
files = list()
for n in xrange( self.images.getNumberPage() ):
self.images.setCurrentPage(n)
if not (self._lines4page[n] or self._text4page[n] or self._img4page[n]) :
files.append(self.images.getImageName())
continue
width, height = self.images.GetWidth(), self.images.GetHeight()
destDC = wx.MemoryDC()
bmp = wx.EmptyBitmap(width, height)
destDC.SelectObject(bmp)
self._privateDraw(destDC)
destDC.SelectObject(wx.NullBitmap)
fo = tempfile.mkstemp(suffix = '%s.png' % n)[1]
bmp.SaveFile(fo, wx.BITMAP_TYPE_PNG)
files.append(fo)
return files
def SetXY(self, event):
x, y = self.ConvertEventCoords(event)
self.x, self.y = x, y
def ConvertEventCoords(self, event):
xView, yView = self.drawPanel.GetViewStart()
xDelta, yDelta = self.drawPanel.GetScrollPixelsPerUnit()
x, y = (event.GetX() + (xView * xDelta),
event.GetY() + (yView * yDelta))
return x / self._getCurrentZoom(), y / self._getCurrentZoom()
def _sizer(self):
#Buttons list
btList = ((self.doPrint, 'printer.jpg', (25,25)), (self.doClose, 'out.png',(25,25)),
(self.doNext, 'next.jpg', (15,15)), (self.doPreview, 'prev.jpg', (15,15)) ,
(self.doRotDx, 'rotdx.jpg',(15,15)), (self.doRotSx, 'rotsx.jpg',(15,15)),
(self.doZoomIn, 'zoomin.jpg',(15,15)), ( self.doZoomOut, 'zoomout.jpg',(15,15)),
)
for inst_but in btList:
bt_name = 'bt' + inst_but[1].split('.')[0]
setattr(self, bt_name , btCtrl(self._p, self.my_path_imgs, inst_but))
self.Bind(wx.EVT_CLOSE, self.doClose)
#Panel
self.drawPanel = wx.ScrolledWindow(self._p, -1, style=wx.SUNKEN_BORDER)
self.drawPanel.EnableScrolling(True, True)
self.drawPanel.SetBackgroundColour(wx.WHITE)
self.drawPanel.Bind(wx.EVT_PAINT, self.doPaint)
self.Bind(wx.EVT_MOUSEWHEEL, self.doMouseWheel)
#if self.modify:
self.drawPanel.Bind(wx.EVT_MOTION, self.doMouseEvt)
self.drawPanel.Bind(wx.EVT_LEFT_DOWN, self.doMouseEvt)
self.drawPanel.Bind(wx.EVT_LEFT_UP, self.doMouseEvt)
for i in (wx.EVT_KEY_DOWN, ):
self.Bind(i, self.doKeyEvt)
self.drawPanel.Bind(i, self.doKeyEvt)
wx.CallAfter(self.drawPanel.SetFocus)
self.panelSizer = wx.BoxSizer(wx.VERTICAL)
#Buttons sizer
self.btSizer = wx.FlexGridSizer(2,11,1,1)
self.btSizer.SetFlexibleDirection(wx.HORIZONTAL)
self.lbl_rotation = wx.StaticText(self._p, -1, 'Rotazione')
self.lbl_pag = wx.StaticText(self._p, -1, 'Pagine')
self.lbl_zoom = wx.StaticText(self._p, -1, 'Zoom')
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(self.lbl_zoom, 0, wx.ALIGN_CENTER)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(self.lbl_rotation ,0, wx.ALIGN_CENTER)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(self.lbl_pag ,0, wx.ALIGN_CENTER)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(wx.Size(0,0),0)
self.btSizer.Add(wx.Size(0,0),0)
self.choZoom = wx.Choice(self._p, -1)
self.choZoom.Bind(wx.EVT_CHOICE, self.doZoomChoice)
self.choZoom.Bind(wx.EVT_MOUSEWHEEL, self.doMouseWheel)
self.choRot = wx.Choice(self._p, -1)
self.choRot.Bind(wx.EVT_CHOICE, self.doRotChoice)
self.choRot.Bind(wx.EVT_MOUSEWHEEL, self.doMouseWheel)
self.choPage = wx.Choice(self._p, -1)
self.choPage.Bind(wx.EVT_CHOICE, self.doPageChoice)
self.choPage.Bind(wx.EVT_MOUSEWHEEL, self.doMouseWheel)
#self.chkA4 = wx.CheckBox(self, -1)
ACV = wx.ALIGN_CENTER_VERTICAL
RLA = wx.RIGHT | wx.LEFT | ACV
#End of line, init the second
self.btSizer.Add(self.btzoomout, 0, RLA, 5)
self.btSizer.Add(self.choZoom, 0, ACV )
self.btSizer.Add(self.btzoomin, 0, RLA, 5)
self.btSizer.Add(self.btrotsx, 0,RLA, 5)
self.btSizer.Add(self.choRot, 0, ACV)
self.btSizer.Add(self.btrotdx, 0,RLA, 5)
self.btSizer.Add(self.btprev, 0,RLA, 5)
self.btSizer.Add(self.choPage, 0, ACV)
self.btSizer.Add(self.btnext, 0,RLA, 5)
#self.btSizer.Add(self.chkA4, 0, RLA,3 )
self.btSizer.Add(self.btprinter, 0,RLA, 5)
self.btSizer.Add(self.btout, 0,RLA, 5)
#Set min size
self.btSizer.SetItemMinSize(self.choRot, wx.Size(70,20))
self.btSizer.SetItemMinSize(self.choZoom, wx.Size(70,20))
self.btSizer.SetItemMinSize(self.choPage, wx.Size(70,20))
#Go with sizer
self.panelSizer.Add(self.btSizer)
self.panelSizer.Add(wx.Size(0,0),0)
self.panelSizer.Add(self.drawPanel, 1, wx.EXPAND | wx.ALL, 10)
self.panelSizer.SetItemMinSize(self.drawPanel, 200, 200)
self._p.SetSizerAndFit(self.panelSizer)
def _getCurrentZoom(self):
""" Return the current zoom
calculated into float value
"""
return float(self.zoom) / 100.0
def _intRotChoice(self, rot):
""" Do the internal rotation choice
"""
self.images.rotateByAngle(rot)
self.drawPanel.Refresh()
def _setRotateChoice(self):
""" Set the right rotation into rotation choice
called from next, previews and _rotate
"""
self.choRot.SetStringSelection('%s' % self.images.getCurrentAngleRotation())
def _privateDraw(self, dc):
""" Do the private draw
"""
dc.BeginDrawing()
bmp = self.images.getCurrentBmp()
dc.DrawBitmap(bmp, 0,0)
for data_bmp in self._img4page[self.images.getCurrentPage()]:
bmp, x,y, w, h = data_bmp
dc.DrawBitmap(bmp, x, y)
for data_line in self._lines4page[self.images.getCurrentPage()]:
for data in data_line:
if len(data) != 3: continue
coords, lw, color = data
dc.SetPen(wx.Pen(color, lw))
x1,y1,x2,y2 = coords
dc.DrawLine(x1,y1,x2,y2)
for data_text in self._text4page[self.images.getCurrentPage()]:
text, x, y, font, color = data_text
dc.SetFont(font)
dc.SetTextForeground(color)
dc.DrawText(text, x, y)
dc.EndDrawing()
def _drawLineTime(self, coords=None, end=None, lw = None, col=None):
""" Draw the lines when the user draw on panel
"""
if end:
if self._dcDrawLines:
self._dcDrawLines.EndDrawing()
self._dcDrawLines = None
return
if not self._dcDrawLines:
self._dcDrawLines = wx.ClientDC(self.drawPanel)
self.drawPanel.PrepareDC(self._dcDrawLines)
self._dcDrawLines.SetUserScale(self._getCurrentZoom(), self._getCurrentZoom())
self._dcDrawLines.BeginDrawing()
if lw: self._dcDrawLines.SetPen(wx.Pen(col, lw))
self._dcDrawLines.DrawLine(*coords)
def _drawObjRect(self, x,y):
"""
"""
dc = wx.ClientDC(self.drawPanel)
self.drawPanel.PrepareDC(dc)
dc.SetUserScale(self._getCurrentZoom(), self._getCurrentZoom())
dc.BeginDrawing()
dc.SetPen(wx.BLACK_DASHED_PEN)
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetLogicalFunction(wx.INVERT)
bH, lH = x - self._textDx, y -self._textDy
W, H = self._obj_size
dc.DrawRectangle(bH, lH, W, H)
dc.EndDrawing()
def _getImageAt(self, x, y, setMoving=1, ctrl_all=False):
"""
"""
if self._moving_img != -1 and not ctrl_all:
return self._img4page[self.images.getCurrentPage()]
for num, img_data in enumerate( self._img4page[self.images.getCurrentPage()] ):
bmp, xTPos, yTPos, xTsize, yTsize = img_data
if ( ( x > xTPos and x < ( xTPos + xTsize ) ) and
( y > yTPos and y < ( yTPos + yTsize) ) ):
self._obj_size = wx.Point(xTsize, yTsize)
if setMoving: self._moving_img = num
return img_data, num
return None
def _getTextAt(self, x, y):
"""
"""
dc = wx.MemoryDC()
bmp = wx.EmptyBitmap(10,10)
dc.SelectObject(bmp)
dc.BeginDrawing()
dc.SetUserScale(self._getCurrentZoom(), self._getCurrentZoom())
dc.SetBackground(wx.WHITE_BRUSH)
for num, t in enumerate( self._text4page[self.images.getCurrentPage()] ):
text, xT, yT, font = t[:4]
dc.Clear()
dc.SetPen(wx.Pen(wx.BLACK, font.GetPointSize(), wx.SOLID))
dc.SetBrush(wx.BLACK_BRUSH)
dc.SetFont(font)
size = dc.GetTextExtent(text)
#dc.EndDrawing()
xTsize = size[0] #* self._getCurrentZoom()
yTsize = size[1] #* self._getCurrentZoom()
xTPos = xT #* self._getCurrentZoom()
yTPos = yT #* self._getCurrentZoom()
if ( x > xTPos and x < ( xTPos + xTsize ) ) and \
(y > yTPos and y < (yTPos + yTsize) ):
self._obj_size = wx.Point(xTsize, yTsize)
return (text, xT, yT, font), num
return None
def _getSideOverBorder(self, x,y):
"""
"""
img_data = self._getImageAt(x,y, False, True)
if not img_data:
return None
xTPos, yTPos, xTsize, yTsize = img_data[0][1:]
N = 10
ll, lr = xTPos - N, xTPos + N
rl, rr = xTPos + xTsize - N, xTPos + xTsize + N
tt, tb = yTPos - N, yTPos + N
bt, bb = yTPos + yTsize - N, yTPos + yTsize + N
img = img_data[0]
if y > bt and y < bb and x > rl and x < rr:
#right bottom
return img, handle_BOTTOM | handle_RIGHT
elif y > tt and y < tb and x > rl and x < rr:
#right top
return img, handle_TOP | handle_RIGHT
elif y > bt and y < bb and x > ll and x < lr:
#left bottom
return img, handle_BOTTOM | handle_LEFT
elif y > tt and y < tb and x > ll and x < lr:
#right top
return img, handle_TOP | handle_LEFT
elif y > tt and y < tb and x > ll and x < (xTPos + xTsize + N):
#top
return img, handle_TOP
elif y > bt and y < bb and x > ll and x < (xTPos + xTsize + N):
#bottom
return img, handle_BOTTOM
elif x > rl and x < rr and y > tt and y < (yTPos + yTsize + N):
#right
return img, handle_RIGHT
elif x > ll and x < lr and y > tt and y < (yTPos + yTsize + N):
#left
return img, handle_LEFT
else:
return None
def _add_image(self, x, y, path=None):
""" Add a new image to the canvas.
If path is passed, not load the file dialog
"""
#new image
if path is None:
path_file = self.opt_cls.get("path_save_preview_img")
path_file = os.path.abspath(path_file)
dlg = wx.FileDialog(self, self.ren.get("select_img"), path_file,
wildcard="*.*")
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
path = dlg.GetPath()
dlg.Destroy()
if not os.path.exists(path):
wx.MessageBox('Image %s not found.' % str(path),
'Error', wx.ICON_ERROR)
return
self.opt_cls.set("path_save_preview_img", os.path.dirname(path))
bmp = wx.Bitmap(path)
if not bmp.Ok(): return
w, h = bmp.GetSize()
data = (bmp, x,y, int(w), int(h))
self._img4page[self.images.getCurrentPage()].append(data)
self._list4undo.append('i')
wx.CallAfter(self.drawPanel.Refresh)
class internalImage(object):
def __init__(self, imgList):
"""Init the class. Pass me the image list
"""
self.imgList = imgList
self.images = list()
self.rotationPage = dict()
for num, x in enumerate(self.imgList):
self.images.append( None )
self.rotationPage[num] = 0
self.currentPage = 0
self.loadImage()
def getNumberPage(self):
""" Return the number of pages
"""
return len(self.imgList)
def GetHeight(self):
"""
"""
return self.images[self.currentPage].GetHeight()
def GetWidth(self):
"""
"""
return self.images[self.currentPage].GetWidth()
def setCurrentPage(self, page):
"""
"""
self.currentPage = page
self.loadImage()
def addToCurrentPage(self, value):
""" Add the value to the current page
"""
self.currentPage += value
def getCurrentPage(self):
"""
"""
return self.currentPage
def getCurrentBmp(self):
""" Return the current image, transformed into bitmap
"""
return wx.BitmapFromImage( self.getCurrentImage())
def getCurrentImage(self):
""" Return the current image
"""
try:
return self.images[self.currentPage]
except:
return wx.EmptyImage(100,100)
def setRotationList(self, list):
"""
"""
self.rotationList = list
def getRotationList(self):
"""
"""
return self.rotationList
def getCurrentAngleRotation(self):
"""
"""
return self.getRotationList()[ self.getRotation() ]
def setRotation(self, angle):
"""
"""
self.rotationPage[self.currentPage] = angle
def getRotation(self):
"""
"""
return self.rotationPage[self.currentPage]
def getPositionAngle(self, angle):
""" Return the position of the angle into the rotation list
Function like list().index(angle), but we don't know
if the caller pass a tuple
"""
for num, i in enumerate(self.getRotationList()):
if i == angle:
return num
raise AttributeError
def addToCurrentRotation(self, value):
"""
"""
self.rotationPage[self.currentPage] += value
def loadImage(self, rotation=0):
""" Method for load only the current page image
"""
#Don't reload the image
if self.getCurrentImage() != None: return
try:
#else load the current page image
self.images = [None for x in range(len(self.imgList) -1) ]
image = wx.Image(self.imgList[self.currentPage])
w, h = image.GetWidth(), image.GetHeight()
if w > h:
image.Rescale(w, w *1.4142)
self.images.insert(self.currentPage, image)
self.__rotateByPos(self.getRotation(), 1)
except:
print traceback.format_exc()
pass
def rotateDx(self):
"""
"""
if self.getRotation() >= 3:
self.setRotation( 0 )
else:
self.addToCurrentRotation( 1 )
self.__rotate(1)
def rotateSx(self):
"""
"""
if self.getRotation() <= 0:
self.setRotation( 3 )
else:
self.addToCurrentRotation( -1 )
self.__rotate(0)
def rotateByAngle(self, rotation):
"""
"""
if not rotation in self.getRotationList():
raise ValueError
pos = self.getPositionAngle(rotation)
self.loadImage()
self.__rotateByPos(pos)
def getImageName(self):
""" Return the current image path/name
"""
return self.imgList[ self.getCurrentPage() ]
def __rotateByPos(self, pos, loadPage=0):
""" Internal method for rotation
Load page is need when I have to set
the initial rotation to a page
"""
if loadPage: self.setRotation(0)
#If are reselected the current zoom, return
currRot = self.getRotation()
if pos == 0 and currRot != 0:
pos = - currRot
if pos == 0: return
elif pos in (1, -3):
self.rotateDx()
elif pos == 2:
self.rotateDx()
self.rotateDx()
elif pos in (3, -1):
self.rotateSx()
elif pos == -2:
self.rotateSx()
self.rotateSx()
def __rotate(self, side):
""" Internal method for rotate the image
"""
self.images[self.getCurrentPage()] = \
self.images[self.getCurrentPage()].Rotate90(side)
class btCtrl(wx.BitmapButton):
def __init__(self, parent, dirImages, values):
doFunct, fileName, size = values
fileName = os.path.join(dirImages, fileName)
wx.BitmapButton.__init__(self, parent, bitmap=wx.NullBitmap,
style=wx.BU_AUTODRAW)
self.Bind(wx.EVT_BUTTON, doFunct)
self.SetBitmapLabel(wx_util.del_mask2img(fileName, size))
class myPrintOut(wx.Printout):
""" Class to perform the printout """
def __init__(self, images, title="Hylapex", text = '', font4print = 0):
wx.Printout.__init__(self, title)
self._images = images
self.pages = images.getNumberPage()
self.currentWorkerPage = images.getCurrentPage()
self.currentPage = 0
self.text = text
self.font4print = font4print
def GetPageInfo(self):
return (1, self.pages, 1, self.pages)
def OnPrintPage(self, page):
dc = self.GetDC()
print 'resolution: %s' % dc.GetPPI()
self._images.setCurrentPage(page-1)
bmap = self._images.getCurrentBmp()
maxX, maxY = bmap.GetWidth(), bmap.GetHeight()
# Let's have at least 50 device units margin
marginX = 10
marginY = 10
# Add the margin to the graphic size
maxX = maxX + (2 * marginX)
maxY = maxY + (2 * marginY)
# Get the size of the DC in pixels
(w, h) = dc.GetSizeTuple()
# Calculate a suitable scaling factor
scaleX = float(w) / maxX
scaleY = float(h) / maxY
# Use x or y scaling factor, whichever fits on the DC
actualScale = min(scaleX, scaleY)
# Calculate the position on the DC for centering the graphic
posX = (w - (maxX * actualScale)) / 2.0
posY = (h - (maxY * actualScale)) / 2.0
# Set the scale and origin
dc.SetUserScale(actualScale, actualScale)
dc.DrawBitmap(bmap, 0, 30, True)
#print the text
if type(self.text) == type(list()):
f = wx.Font(int(self.font4print), wx.DEFAULT , wx.ITALIC, wx.BOLD)
dc.SetFont(f)
dc.SetDeviceOrigin(0,0)
text_sx = self.text[0]
text_ce = self.text[1]
text_dx = self.text[2] + ' -- Pag. ' + str(page) + ' di ' + str(self.pages)
dim_sx = dc.GetTextExtent(text_sx)[0]
dim_ce = dc.GetTextExtent(text_ce)[0]
dim_dx = dc.GetTextExtent(text_dx)[0]
pos_sx = int(marginX*3)
pos_ce = int( (maxX / 2) - (dim_ce / 2) )
pos_dx = int( maxX - ( dim_dx + marginX*3 ) )
if sys.platform == 'win32':
marginY = 0
else:
marginY = 30
dc.DrawText(text_sx, pos_sx , marginY)
dc.DrawText(text_ce, pos_ce , marginY)
dc.DrawText(text_dx, pos_dx , marginY)
#Re-set the current worker page
if self.pages == page:
self._images.setCurrentPage(self.currentWorkerPage)
return True
def HasPage(self, page):
if page <= self.pages:
return True
else:
return False
def OnBeginDocument(self, stpg, endpg):
if not wx.Printout.OnBeginDocument(self, stpg, endpg):
return False
return True
class MyApp(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
if len(sys.argv) > 1:
self.main = Img_view(None, sys.argv[1:], only4test=1)
else:
print "Load me with '%s image'" % sys.argv[0]
return False
self.main.Show()
return True
if __name__ == '__main__':
app = MyApp(0)
app.MainLoop()
|