Printing an image
Brian Wolf
brian.wolf at activustech.com
Mon Jul 2 14:50:37 PDT 2007
Many thanks to Andrea G. for helping me with an image viewer widget. I =
added a slider control to the document viewer, which lets the user =
select zoom (magnification) at many (various) amounts. Please find =
scripts attached.
[NOTE: Paradigm: Each document consists of 1 or more images (pages), and =
it's referenced by a document ID. Each page is referenced by a page ID. =
The docviewer assumes that a document ID is passed to it.]
Brian
-------------- next part --------------
import wx
from PIL import Image
def BitmapToPil(bitmap):
return ImageToPil(BitmapToImage(bitmap))
def BitmapToImage(bitmap):
return wx.ImageFromBitmap(bitmap)
def PilToBitmap(pil):
return ImageToBitmap(PilToImage(pil))
def PilToImage(pil):
image =3D wx.EmptyImage(pil.size[0], pil.size[1])
image.SetData(pil.convert('RGB').tostring())
return image
def PiltoImageAlpha(pil, alpha=3DTrue):
if alpha:
image =3D apply(wx.EmptyImage, pil.size)
image.SetData(pil.convert( "RGB").tostring())
image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
else:
image =3D wx.EmptyImage(pil.size[0], pil.size[1])
new_image =3D pil.convert('RGB')
data =3D new_image.tostring()
image.SetData(data)
return image
def ImageToPil(image):
pil =3D Image.new('RGB',(image.GetWidth(), image.GetHeight()))
pil.fromstring(image.GetData())
return pil
def ImageToBitmap(image):
return image.ConvertToBitmap()
-------------- next part --------------
import wx
from PIL import Image
import ImageFile
from components.docmgr import DocMgr
import components.image_utils as imgutils
from ScrolledImage import ScrolledImage
from types import *
class DocViewer(wx.Frame):
def __init__(self, parent, doc_id, title=3D'Document Viewer'):
self.title =3D title
wx.Frame.__init__(self, parent, size=3D(800, 600), title=3Dtitle, name=3D=
'docviewer')
self.CenterOnScreen()
# get pages for the given document
self.doc_id =3D doc_id
docm =3D DocMgr()
self.pagelist =3D docm.GetPages(doc_id)
self.SetBackgroundColour('#cecece')
# main sizer
mainsizer =3D wx.BoxSizer(wx.VERTICAL)
# display area
displayareasizer =3D wx.GridSizer(1,1,0,0)
self.displayarea =3D ScrolledImage(self)
self.displayarea.SetBackgroundColour('#cecece')
displayareasizer.Add(self.displayarea, 1, wx.ALL | wx.EXPAND, 1)
mainsizer.Add(displayareasizer, 1, wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, =
1)
# slider
slidersizer =3D wx.BoxSizer(wx.HORIZONTAL)
sliderstyle =3D wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS | wx.SL=
_SELRANGE
slider =3D wx.Slider(self, size=3D(400,-1), style=3Dsliderstyle)
slider.SetRange(25, 400)
slider.SetTickFreq(25)
slider.SetValue(100)
slidersizer.Add(slider, 0, wx.ALIGN_CENTER | wx.ALL, 1)
mainsizer.Add(slidersizer, 0, wx.ALIGN_CENTER | wx.ALL, 1)
slider.Bind(wx.EVT_SCROLL_ENDSCROLL, self.OnEndScroll)
slider.Bind(wx.EVT_COMMAND_SCROLL_THUMBTRACK, self.OnThumbTrack)
# navbar
navbarsizer =3D wx.BoxSizer(wx.HORIZONTAL)
mainsizer.Add(navbarsizer, 0, wx.ALIGN_CENTER | wx.ALL, 1)
# set current document position
page_cnt =3D len(self.pagelist)
self.cur_pos =3D min(1, page_cnt)
# create navigation buttons
navlist =3D ['ID_FIRST','ID_PREVIOUS','ID_CURRENT','ID_NEXT','ID_LAST']
self.navdict =3D {}
for nav in navlist:
self.navdict[nav] =3D wx.NewId()
self.first =3D wx.Button(self, id=3Dself.navdict['ID_FIRST'], label=3D'<<=
First', name=3D'first')
self.previous =3D wx.Button(self, id=3Dself.navdict['ID_PREVIOUS'], label=
=3D'< Previous', name=3D'previous')
cur_pos_label =3D ' ' + str(self.cur_pos) + ' of ' + str(page_cnt) + ' '
self.cur_pos_ind =3D wx.StaticText(self, id=3Dself.navdict['ID_CURRENT'],=
label=3Dcur_pos_label, style=3Dwx.SIMPLE_BORDER)
self.next =3D wx.Button(self, id=3Dself.navdict['ID_NEXT'], label=3D'Next=
>', name=3D'next')
self.last =3D wx.Button(self, id=3Dself.navdict['ID_LAST'], label=3D'Last=
>>', name=3D'last')
# add nav buttons to sizer
staticbox =3D wx.StaticBox(self, wx.ID_ANY, _('Navigation'))
staticmainsizer =3D wx.StaticBoxSizer(staticbox, wx.HORIZONTAL)
staticmainsizer.Add(self.first, 0, wx.ALL, 2)
staticmainsizer.Add(self.previous, 0, wx.ALL, 2)
staticmainsizer.Add(self.cur_pos_ind, 0, wx.ALL | wx.ALIGN_CENTER, 5)
staticmainsizer.Add(self.next, 0, wx.ALL, 2)
staticmainsizer.Add(self.last, 0, wx.ALL, 2)
navbarsizer.Add(staticmainsizer, 0, wx.FIXED_MINSIZE | wx.ALIGN_CENTER_HO=
RIZONTAL, 5)
navbarsizer.Add((10,10))
# bind navigation buttons
for key in navlist:
self.Bind(wx.EVT_BUTTON, self.OnButton, id=3Dself.navdict[key])
# action buttons
staticbox =3D wx.StaticBox(self, wx.ID_ANY, _('Actions'))
staticmainsizer =3D wx.StaticBoxSizer(staticbox, wx.HORIZONTAL)
btn_print =3D wx.Button(self, id=3Dwx.ID_PRINT)
btn_close =3D wx.Button(self, id=3Dwx.ID_CLOSE)
##btn_zoom_in =3D wx.Button(self, id=3Dwx.ID_CLOSE)
##btn_zoom_out =3D wx.Button(self, id=3Dwx.ID_CLOSE)
staticmainsizer.Add(btn_print, 0, wx.ALL, 2)
staticmainsizer.Add(btn_close, 0, wx.ALL, 2)
##staticmainsizer.Add(btn_zoom_in, 0, wx.ALL, 2)
##staticmainsizer.Add(btn_zoom_out, 0, wx.ALL, 2)
self.Bind(wx.EVT_BUTTON, self.OnButton, id=3Dwx.ID_CLOSE)
self.Bind(wx.EVT_BUTTON, self.OnButton, id=3Dwx.ID_PRINT)
navbarsizer.Add(staticmainsizer, 0, wx.FIXED_MINSIZE | wx.ALIGN_CENTER_HO=
RIZONTAL, 5)
# complete sizer for this widget
self.SetSizer(mainsizer)
self.Layout()
# set current position
self._SetNav()
self.Refresh()
# ------------------------------------------------------------
def _SetNav(self):
if self.cur_pos =3D=3D 0:
self.first.Disable()
self.previous.Disable()
self.next.Disable()
self.last.Disable()
elif self.cur_pos =3D=3D 1:
self.first.Disable()
self.previous.Disable()
if self.cur_pos < len(self.pagelist):
self.next.Enable()
self.last.Enable()
else:
self.next.Disable()
self.last.Disable()
elif self.cur_pos =3D=3D len(self.pagelist):
if self.cur_pos > 1:
self.first.Enable()
self.previous.Enable()
self.next.Disable()
self.last.Disable()
else:
self.first.Enable()
self.previous.Enable()
self.next.Enable()
self.last.Enable()
cur_pos_label =3D ' ' + str(self.cur_pos) + ' of ' + str(len(self.pagelis=
t)) + ' '
self.cur_pos_ind.SetLabel(cur_pos_label)
self.ShowImage()
# ------------------------------------------------------------
def OnButton(self, event):
button =3D event.GetEventObject()
btn_id =3D event.GetId()
# process action buttons
if btn_id =3D=3D wx.ID_CLOSE:
self.OnClose(event)
return
elif btn_id =3D=3D wx.ID_PRINT:
self.OnPrint(event)
return
# make sure there's at least one document
if len(self.pagelist) =3D=3D 0: return
if btn_id =3D=3D self.navdict['ID_FIRST']:
self.cur_pos =3D 1
self._SetNav()
elif btn_id =3D=3D self.navdict['ID_PREVIOUS']:
if self.cur_pos =3D=3D 1: return
self.cur_pos +=3D -1
self._SetNav()
elif btn_id =3D=3D self.navdict['ID_NEXT']:
if self.cur_pos =3D=3D len(self.pagelist): return
self.cur_pos +=3D 1
self._SetNav()
elif btn_id =3D=3D self.navdict['ID_LAST']:
self.cur_pos =3D len(self.pagelist)
self._SetNav()
# ------------------------------------------------------------
def OnClose(self, event):
self.Destroy()
# ------------------------------------------------------------
def OnPrint(self, event):
page =3D self.pagelist[self.cur_pos - 1]
=
# ------------------------------------------------------------
def ShowImage(self):
# get current page
page =3D self.pagelist[self.cur_pos - 1]
# set wx.bitmap from python buffer object
p =3D ImageFile.Parser()
p.feed(page.image)
im =3D p.close()
self.bmp =3D imgutils.PilToBitmap(im)
self.displayarea.ShowImage(self.bmp)
# ------------------------------------------------------------
def OnEndScroll(self, event):
slider =3D event.GetEventObject()
value =3D slider.GetValue()
self.displayarea.SetZoom(value)
# ------------------------------------------------------------
def OnThumbTrack(self, event):
slider =3D event.GetEventObject()
value =3D slider.GetValue()
event.Skip()
-------------- next part --------------
import math
from components.image_utils import *
class ScrolledImage(wx.ScrolledWindow):
def __init__(self, parent):
wx.ScrolledWindow.__init__(self, parent)
self.scale =3D 1.
self.size =3D wx.Size(0, 0)
self.SetExtraStyle(0)
self.backcolour =3D wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.currentbmp =3D None
# ------------------------------------------------------------
def OnPaint(self, event):
self.SetScale(1./self.scale, 1./self.scale)
dc =3D wx.PaintDC(self)
dc.SetBackground(wx.Brush(self.backcolour))
iw, ih =3D self.size
dc.Clear()
self.DoPaint(dc)
del dc
self.SetScale(1, 1)
=
# ------------------------------------------------------------
def DoPaint(self, dc=3DNone):
if self.currentbmp =3D=3D None: return
if dc is None:
dc =3D wx.ClientDC(self)
self.PrepareDC(dc)
iw, ih =3D self.size
xmin =3D (self.windowsize.x - iw)/2
ymin =3D (self.windowsize.y - ih)/2
bm_dc =3D wx.MemoryDC()
bm_dc.SelectObject(self.currentbmp)
if xmin < 0:
xmin =3D 0
if ymin < 0:
ymin =3D 0
dc.Blit(xmin*self.scale, ymin*self.scale, iw*self.scale, ih*self.scale, b=
m_dc, 0, 0, wx.COPY, True)
bm_dc.SelectObject(wx.NullBitmap)
# ------------------------------------------------------------
def OnSize(self, event):
iw, ih =3D self.size.width, self.size.height
w, h =3D event.GetSize()
scroll_x =3D w < iw
scroll_y =3D h < ih
scroll =3D scroll_x | scroll_y
x, y =3D self.GetViewStart()
self.SetScrollbars(scroll,scroll,iw,ih,x,y)
self.windowsize =3D wx.Size(w, h)
# ------------------------------------------------------------
def ShowImage(self, bmp):
self.currentbmp =3D bmp
self.size =3D wx.Size(self.currentbmp.GetSize().width*self.scale, self.cu=
rrentbmp.GetSize().height*self.scale)
self.SetZoom(100)
self.Refresh()
# ------------------------------------------------------------
def SetZoom(self, factor):
# change to absolute number if given as percentage
if factor > 10:
factor /=3D 100.
# calculate scale amount
calc_scale =3D 1./factor
# use calculated scale amount to resize bitmap
self.SetScale(1, 1)
self.GetParent().SetSizeHints(-1,-1,-1,-1)
x, y =3D self.GetViewStart()
cw, ch =3D self.GetClientSize()
midx, midy =3D x + cw / 2, y + ch / 2
midx /=3D float(self.size.width)
midy /=3D float(self.size.height)
# set scale based upon zoom setting
self.scale =3D calc_scale
self.size =3D wx.Size(self.currentbmp.GetSize().width/self.scale, self.cu=
rrentbmp.GetSize().height/self.scale)
iw, ih =3D self.size.width, self.size.height
w, h =3D self.GetSize()
scroll_x =3D w < iw
scroll_y =3D h < ih
x, y =3D self.GetViewStart()
new_midx =3D midx * self.size.width
new_midy =3D midy * self.size.height
x =3D new_midx - cw/2
y =3D new_midy - ch/2
self.SetScrollbars(scroll_x,scroll_y,iw,ih,x,y)
zoom_percent =3D round((1./self.scale)*100, 2)
if zoom_percent =3D=3D math.floor(zoom_percent):
zoom_percent =3D str(zoom_percent).rstrip('0')[:-1]
self.SetScale(self.scale, self.scale)
More information about the wxpython-users
mailing list