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