This example shows a PDF Viewer class, which handles things like Zoom and Scrolling. It requires python-poppler and wxPython >= 2.8.9.
Python, 112 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
#!/usr/bin/env python # coding: utf-8 """ wxPDFViewer - Simple PDF Viewer using Python-Poppler and wxPython Marcelo Fidel Fernandez - BSD License http://www.marcelofernandez.info - firstname.lastname@example.org """ import wx import wx.lib.wxcairo as wxcairo import sys import poppler class PDFWindow(wx.ScrolledWindow): """ This example class implements a PDF Viewer Window, handling Zoom and Scrolling """ MAX_SCALE = 2 MIN_SCALE = 1 SCROLLBAR_UNITS = 20 # pixels per scrollbar unit def __init__(self, parent): wx.ScrolledWindow.__init__(self, parent, wx.ID_ANY) # Wrap a panel inside self.panel = wx.Panel(self) # Initialize variables self.n_page = 0 self.scale = 1 self.document = None self.n_pages = None self.current_page = None self.width = None self.height = None # Connect panel events self.panel.Bind(wx.EVT_PAINT, self.OnPaint) self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.panel.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.panel.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) def LoadDocument(self, file): self.document = poppler.document_new_from_file("file://" + file, None) self.n_pages = self.document.get_n_pages() self.current_page = self.document.get_page(self.n_page) self.width, self.height = self.current_page.get_size() self._UpdateSize() def OnPaint(self, event): dc = wx.PaintDC(self.panel) cr = wxcairo.ContextFromDC(dc) cr.set_source_rgb(1, 1, 1) # White background if self.scale != 1: cr.scale(self.scale, self.scale) cr.rectangle(0, 0, self.width, self.height) cr.fill() self.current_page.render(cr) def OnLeftDown(self, event): self._UpdateScale(self.scale + 0.2) def OnRightDown(self, event): self._UpdateScale(self.scale - 0.2) def _UpdateScale(self, new_scale): if new_scale >= PDFWindow.MIN_SCALE and new_scale <= PDFWindow.MAX_SCALE: self.scale = new_scale # Obtain the current scroll position prev_position = self.GetViewStart() # Scroll to the beginning because I'm going to redraw all the panel self.Scroll(0, 0) # Redraw (calls OnPaint and such) self.Refresh() # Update panel Size and scrollbar config self._UpdateSize() # Get to the previous scroll position self.Scroll(prev_position, prev_position) def _UpdateSize(self): u = PDFWindow.SCROLLBAR_UNITS self.panel.SetSize((self.width*self.scale, self.height*self.scale)) self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u) def OnKeyDown(self, event): update = True # More keycodes in http://docs.wxwidgets.org/stable/wx_keycodes.html#keycodes keycode = event.GetKeyCode() if keycode in (wx.WXK_PAGEDOWN, wx.WXK_SPACE): next_page = self.n_page + 1 elif keycode == wx.WXK_PAGEUP: next_page = self.n_page - 1 else: update = False if update and (next_page >= 0) and (next_page < self.n_pages): self.n_page = next_page self.current_page = self.document.get_page(next_page) self.Refresh() class MyFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, "wxPdf Viewer", size=(800,600)) self.pdfwindow = PDFWindow(self) self.pdfwindow.LoadDocument(sys.argv) self.pdfwindow.SetFocus() # To capture keyboard events if __name__=="__main__": app = wx.App() f = MyFrame() f.Show() app.MainLoop()
Tags: pdf, poppler, python_poppler, viewer, wxpython
This gives me segmentation fault on line 50: cr = wxcairo.ContextFromDC(dc)
Perhaps it works nice under valgrind. What can it be?
It works fine here, in my Ubuntu 11.04 installation. Could you describe what's you system environment, python and library versions?
I have programmed with the code you have done a full pdf reader with Python! But I need your help: I have many pdf with images inside, and the Cairo back-ends for Poppler aren't good to work with images: the scrolling is very slow. I know that there are other back-ends for drawing pdf documents: Splash. But I cannot find anything: no documentation or tutorials about it. Can you help me?
Thank you so much.
Try Evince, which uses poppler-cairo (but from C) to render.
If it is faster, I guess the problem with the slow scrolling for complex pdfs isn't in the backend but in the OnPaint() method. It redraws all the GC context instead of moving the old part and after that, just render the new one (on the top or bottom, depending of the scroll direction).
I'm accepting patches to improve this behavior. :-)
Regards, Marcelo PD: You can see the Evince source code to see how it handles this situation.
I know Evince, and I use it for read my pdfs. But I need to underline pdfs I have scanned, and with Evince it is impossible. Sometimes I use Xournal for my tasks, but i want to underline with straight lines, not paint on with standard Xournals tool. So I'm doing the software that I need by myself, but I don't know C, only a bit of Python. I have read that Cairo works well with vector graphic and not with raster graphic. Maybe Splash works better with raster graphic. Or maybe I have to learn C !
I said that if Evince is faster to render that kind of pdfs when scrolling, I guess the issue is in the OnPaint() method because it uses the same library and backend than this example.
I understand now! I'll see if I can find a good workaround for OnPaint() method.
I'll write again if I'll find something better.
please share, I am also looking at making Python pdf viewer with annotations and highlighting.