var tipuesearch = {"pages":[{"title":"About","text":"I set up this blog when I started out learning Python with every intention to post new things as I learned them. It was going to be great. I'd learn new things and then type them up so that I'd have notes to refer back to and so that others could learn from the mistakes I'd made along the way. It turns out that just typing into a note taking application is easier. I started with programming back when I was 12 in BASIC on an Amstrad CPC 464. I played with Visual Basic and Delphi as a hobby in my teens but didn't really get very far with either. I didn't plan on becoming a developer as a career, but that happened accidentally when I started working at an office in Manchester. It turns out many small, time consuming tasks can be replaced with scripts and that evolved into desktop application and web development before I realised what was happening. After having tried out a few tools I mainly use Python with PyQt for desktop and Django/Flask for web and am enjoying learning new things as I go. I might write some of those things up here. Or I might just type them into my notebook.","tags":"pages","url":"https://overthere.co.uk/about/","loc":"https://overthere.co.uk/about/"},{"title":"Bing Wallpaper Changer","text":"About This program will run in the system tray and check for a new daily Bing image on a user defined interval. If the URL for the image has changed since the last check the new image will be downloaded and applied as the current wallpaper. There is also the option to run a command after the wallpaper has been applied. This is useful for anyone that uses software that overlays data onto their wallpaper, Such as BgInfo from Sysinternals. The last two week's worth of images is available on a History tab - just double click a thumbnail to apply a wallpaper. If using this and you want to keep an old wallpaper don't forget to disable to the automatic updating from the main Settings tab, otherwise the wallpaper will be replaced with the daily wallpaper on the next update check. Why? I don't use Bing as a search engine, but I do very much like their daily images. I was excited when I first heard about the official Bing Desktop application, but wasn't keen on the toolbar that was added to my desktop. I tried to just live with it for a while but it caused problems with a few full screen applications when it refreshed. After not being able to find a similar program with the features I wanted I decided to write my own. Screenshots Changelog 1.6 Added support for extra desktop environments under Linux. Improved performance of History tab when loading images from disk. Ability to switch between black and white icon for system tray. 1.5 Ability to save images to a custom folder. Increased History tab range back up to 3 weeks; duplicate dates will be ignored. 1.4 Command line switches for closing after applying wallpaper (—quit). 1.3 Added ability to set old Bing wallpapers from the History tab by double clicking the thumbnail. Reduced History tab range from three weeks to two as duplicates were shown when Bing had featured interactive images on the homepage. 1.2 Added option to system tray menu to directly open settings page. Wallpaper change is now permanent and should be retained after logoff/shutdown. Switched to Qt downloading methods instead of Python. Initial Linux support added in source. Tested on Ubuntu 13.04 - working fine apart from QSystemTrayIcon not being displayed. Need to find how that's handled in Ubuntu now… 1.1 Added Settings and History tabs to the main window. Fixed broken refresh when current Bing image is the same as previously downloaded image. GUI fixes. 1.0 First release with basic functionality. Download Version 1.6 (~9.1 MB )","tags":"Software","url":"https://overthere.co.uk/bing-wallpaper-changer/","loc":"https://overthere.co.uk/bing-wallpaper-changer/"},{"title":"Convert local path to UNC path in Python","text":"I recently had the need to convert a local path to a UNC path for an application I was writing. The application monitors a local folder for files and serves them to a client over the network as requested, but for the client to be able to access the file the path had to be a UNC path. There didn't seem to be a built in way to do this in Python so here's what I ended up with. When the NetworkPaths class is initialised it will build a dictionary of available Windows shares on the current machine with the path as the key and share name as the value. It then creates a list of the share paths ordered by longest first. When the convert method is given a path it works through the list of stored share paths checking to see if any match the start of the given path. If a match is found it builds the UNC path using the dictionary lookup to get the share name. class NetworkPaths ( object ): def __init__ ( self ): super ( NetworkPaths , self ) . __init__ () obj_wmi_service = win32com . client . Dispatch ( 'WbemScripting.SWbemLocator' ) obj_s_wbem_services = obj_wmi_service . ConnectServer ( '.' , 'root\\cimv2' ) items = obj_s_wbem_services . ExecQuery ( 'SELECT * FROM Win32_Share' ) self . shares_lookup = { str ( share . Path ): str ( share . Name ) for share in items if share . Path and not '$' in share . Name and not share . Name == 'Users' } self . shares = sorted (( x for x in self . shares_lookup . keys ()), key = len , reverse = True ) def convert ( self , local_path ): if local_path [: 2 ] == ' \\\\\\\\ ' : # Path is already UNC. return local_path for share_path in self . shares : if local_path . lower () . startswith ( share_path . lower ()): # We have a match. Return the UNC path. if local_path [ len ( share_path )] == ' \\\\ ' : path_end = local_path [ len ( share_path ) + 1 :] else : path_end = local_path [ len ( share_path ):] unc_path = os . path . join ( ' \\\\\\\\ {0:s} ' . format ( os . getenv ( 'COMPUTERNAME' )), self . shares_lookup [ share_path ], path_end ) return unc_path # No match found. return None For example, given the path C:\\Users\\Gary Hughes\\Desktop\\Batch Files\\Full Backup.bat on my machine: network_paths = NetworkPaths () print network_paths . convert ( r 'C:\\Users\\Gary Hughes\\Desktop\\Batch Files\\Full Backup.bat' ) returns: \\\\IRUSH\\Desktop\\Batch Files\\Full Backup.bat With the paths sorted by longest first this should ensure the shortest UNC path is returned.","tags":"Tutorials","url":"https://overthere.co.uk/2014/09/02/python-local-path-to-unc/","loc":"https://overthere.co.uk/2014/09/02/python-local-path-to-unc/"},{"title":"Bing Wallpaper Changer","text":"About This program will run in the system tray and check for a new daily Bing image on a user defined interval. If the URL for the image has changed since the last check the new image will be downloaded and applied as the current wallpaper. There is also the option to run a command after the wallpaper has been applied. This is useful for anyone that uses software that overlays data onto their wallpaper, Such as BgInfo from Sysinternals. The last two week's worth of images is available on a History tab - just double click a thumbnail to apply a wallpaper. If using this and you want to keep an old wallpaper don't forget to disable to the automatic updating from the main Settings tab, otherwise the wallpaper will be replaced with the daily wallpaper on the next update check. New Version Since this blog post I've posted new versions. Take a look at the Bing Wallpaper Changer page. Why? I don't use Bing as a search engine, but I do very much like their daily images. I was excited when I first heard about the official Bing Desktop application, but wasn't keen on the toolbar that was added to my desktop. I tried to just live with it for a while but it caused problems with a few full screen applications when it refreshed. After not being able to find a similar program with the features I wanted I decided to write my own. Changelog 1.3 Added ability to set old Bing wallpapers from the History tab by double clicking the thumbnail. Reduced History tab range from three weeks to two as duplicates were shown when Bing had featured interactive images on the homepage. 1.2 Added option to system tray menu to directly open settings page. Wallpaper change is now permanent and should be retained after logoff/shutdown. Switched to Qt downloading methods instead of Python. Initial Linux support added in source. Tested on Ubuntu 13.04 - working fine apart from QSystemTrayIcon not being displayed. Need to find how that's handled in Ubuntu now… 1.1 Added Settings and History tabs to the main window. Fixed broken refresh when current Bing image is the same as previously downloaded image. GUI fixes. 1.0 First release with basic functionality.","tags":"Software","url":"https://overthere.co.uk/2013/09/01/bing-wallpaper-changer/","loc":"https://overthere.co.uk/2013/09/01/bing-wallpaper-changer/"},{"title":"Improving PyPDF2 with PDFtk","text":"PyPDF2 (forked from pyPdf ) is wonderful. I use it a fair bit in my job, mainly for chopping up PDFs and re-assembling the pages in a different order. It does sometimes have difficulty with non-standard PDFs though that seem fine in other programs. This can be frustrating. The one that I've been battling with today from some PDFs provided by a client was: PyPDF2 . utils . PdfReadError : EOF marker not found I managed to find a workaround using PDFtk to fix the PDF in memory at the first sign of any trouble. It works well so far, so in case anyone else is having similar issues I thought I'd write it up. So here's how I was opening PDF files before. from PyPDF2 import PdfFileReader from cStringIO import StringIO input_path = 'c:/test_in.pdf' with open ( input_path , 'rb' ) as input_file : input_buffer = StringIO ( input_file . read ()) input_pdf = PdfFileReader ( input_buffer ) At that point you're free to do whatever it is you want to do with input_pdf . Providing of course that it loaded without issue. I'm loading the file into a StringIO object first for speed; the program this is from does lots of things with the file and StringIO made things much faster. So to work around the EOF problem I add a new decompress_pdf function that gets called if there's a problem parsing the PDF . It takes the data from the StringIO and sends it to a PDFtk process on stdin that simply runs PDFtk's uncompress command on the data. The fixed PDF is read back from stdout and returned as a StringIO , where things will hopefully carry on as if nothing happened. from PyPDF2 import PdfFileReader , utils from cStringIO import StringIO import subprocess input_path = 'c:/test_in.pdf' def decompress_pdf ( temp_buffer ): temp_buffer . seek ( 0 ) # Make sure we're at the start of the file. process = subprocess . Popen ([ 'pdftk.exe' , '-' , # Read from stdin. 'output' , '-' , # Write to stdout. 'uncompress' ], stdin = temp_buffer , stdout = subprocess . PIPE , stderr = subprocess . PIPE ) stdout , stderr = process . communicate () return StringIO ( stdout ) with open ( input_path , 'rb' ) as input_file : input_buffer = StringIO ( input_file . read ()) try : input_pdf = PdfFileReader ( input_buffer ) except utils . PdfReadError : input_pdf = PdfFileReader ( decompress_pdf ( input_file )) The problem I was seeing seemed to be because of invalid characters appearing after the %% EOF marker in the PDF . PDFtk seems better at fixing this and spits out a valid PDF when the uncompress command is used. Of course, more error detection would be good in case parsing still fails, but this worked for me today and made me happy.","tags":"Tutorials","url":"https://overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/","loc":"https://overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/"},{"title":"New Blog!","text":"I've moved this site from WordPress to Pelican . Pelican is awesome. WordPress is written in PHP and uses MySQL to store the data needed to build each page. The good thing about WordPress is that the pages are built as they are requested. The bad thing about WordPress is that the pages are built as they are requested. The whole database-driven dynamic page thing can slow down a site quite a bit, especially if you're only using a basic hosting package. If like me you also install a boatload of plugins and themes to test things out the database gets full of cruft adding to more slowdowns. I experimented with various different caching plugins and they seemed to work great for a couple of weeks and then they'd stop updating the content and serve up week-old stale pages. I never found out why. So a caching plugin basically saves a copy of a generated page as a static HTML file and serves it back up if the page is requested again instead of having to recreate it. It's a way of turning your nice dynamic site into a static site. So why not just have a static site? Well, it's good to have themes, plugins and control over other parts of the site to be able to change things quickly. It's also nice to have a nice interface for writing posts. While looking for alternative blogging platforms that might improve the speed of my site I stumbled across Pelican. The fact that it's written in Python had me interested right away. Pelican doesn't require any kind of fiddly setting up of the web host, it just parses a config file with site settings, takes posts written in single Markdown files and creates a static HTML site. When you add a new post by creating a new Markdown file the whole site can be regenerated again. Very quickly. Tie this with rsync for quick deployment back to the web host and you have a very customisable and fast blogging solution that's also fun to use. I started out with a couple of the default themes with my own tweaks, but have finally settled on a Pelican port of the default Octopress (similar to Pelican but Ruby based) theme by Maurizio Sambati along with some excellent modifications by Jake Vanderplas . I'm very much happy with the results.","tags":"Blog","url":"https://overthere.co.uk/2013/06/14/new-blog/","loc":"https://overthere.co.uk/2013/06/14/new-blog/"},{"title":"QGraphicsView with mouse wrapping","text":"In a document management program that I'm writing I'm displaying images in a QGraphicsView . The QGraphicsView supports a drag mode that allows a user to simply click and drag within the view to pan around, which works great when a large image is displayed and the user has zoomed in quite far. Panning the image this way does mean that the user has to click back on the image and move the mouse again when the mouse reaches the end of the screen. I needed a way to implement mouse wrapping so that when the mouse reaches the end of the QGraphicsView during panning and the user is still holding down the left mouse button the mouse will jump to the opposite edge, giving a smooth continuous pan. Here's what I came up with… from PyQt4.QtCore import Qt , QEvent , QTimer from PyQt4.QtGui import QWidget , QGraphicsView , QVBoxLayout , \\ QApplication , QGraphicsScene , QBrush , QColor , QMouseEvent , \\ QCursor class GraphicsView ( QGraphicsView ): def mouseMoveEvent ( self , event ): width , height = self . width (), self . height () event_x , event_y = event . x (), event . y () if event_y < 0 or event_y > height or \\ event_x < 0 or event_x > width : # Mouse cursor has left the widget. Wrap the mouse. global_pos = self . mapToGlobal ( event . pos ()) if event_y < 0 or event_y > height : # Cursor left on the y axis. Move cursor to the # opposite side. global_pos . setY ( global_pos . y () + ( height if event_y < 0 else - height )) else : # Cursor left on the x axis. Move cursor to the # opposite side. global_pos . setX ( global_pos . x () + ( width if event_x < 0 else - width )) # For the scroll hand dragging to work with mouse wrapping # we have to emulate a mouse release, move the cursor and # then emulate a mouse press. Not doing this causes the # scroll hand drag to stop after the cursor has moved. r_event = QMouseEvent ( QEvent . MouseButtonRelease , self . mapFromGlobal ( QCursor . pos ()), Qt . LeftButton , Qt . NoButton , Qt . NoModifier ) self . mouseReleaseEvent ( r_event ) QCursor . setPos ( global_pos ) p_event = QMouseEvent ( QEvent . MouseButtonPress , self . mapFromGlobal ( QCursor . pos ()), Qt . LeftButton , Qt . LeftButton , Qt . NoModifier ) QTimer . singleShot ( 0 , lambda : self . mousePressEvent ( p_event )) else : QGraphicsView . mouseMoveEvent ( self , event ) class Widget ( QWidget ): def __init__ ( self , parent = None ): QWidget . __init__ ( self , parent ) self . scene = QGraphicsScene () self . scene . setSceneRect ( - 5000 , - 5000 , 5000 , 5000 ) self . g_view = GraphicsView ( self . scene ) self . g_view . setBackgroundBrush ( QBrush ( QColor ( 'black' ), Qt . DiagCrossPattern )) self . g_view . setDragMode ( QGraphicsView . ScrollHandDrag ) self . g_view . scale ( 5 , 5 ) v_layout = QVBoxLayout () v_layout . addWidget ( self . g_view ) self . setLayout ( v_layout ) if __name__ == '__main__' : import sys app = QApplication ( sys . argv ) widget = Widget () widget . show () sys . exit ( app . exec_ ()) The code above uses a sub-classed QGraphicsView . The mousePressEvent checks to see if the mouse cursor has left the QGraphicsView ; if it has then it moves the mouse to the opposite edge. The bit that had me stuck were the mouseReleaseEvent and mousePressEvent calls. When moving the cursor the drag was still active, so the image just panned back as if the user had moved the mouse. The mouse events are called to simulate releasing the mouse button, moving the pointer and then pressing the mouse button again. This gives a smooth continuous pan until you run out of either image or desk space :).","tags":"Tutorials","url":"https://overthere.co.uk/2012/11/29/qgraphicsview-with-mouse-wrapping/","loc":"https://overthere.co.uk/2012/11/29/qgraphicsview-with-mouse-wrapping/"},{"title":"Using QStyledItemDelegate on a QTableView","text":"Most databases store dates in the format YYYY-MM-DD . When using a QTableView to display a database table in PyQt it's useful to be able to display this in a different format. Being from the UK I'd rather have the date displayed in the UK style – DD/MM/YYYY . This is where QStyledItemDelegate comes in. I'd put off looking into this for a while because whenever I tried to look in to using QStyledItemDelegate I saw people mentioning paint methods. I know nothing about painting in PyQt and get quite scared when I see it mentioned. I really need to get over that. Not to worry though, because it's not needed… Just subclass QStyledItemDelegate and have it take the variable date_format in its __init__ method: class DateFormatDelegate ( QStyledItemDelegate ): def __init__ ( self , date_format ): QStyledItemDelegate . __init__ ( self ) self . date_format = date_format def displayText ( self , value , locale ): return value . toDate () . toString ( self . date_format ) This way we can customise the date format without changing the class making it a little more portable. On your QTableView call setItemDelegateForColumn() and pass it your column index and a new instance of your subclassed QStyledItemDelegate with a date format: self . tableResults . setItemDelegateForColumn ( 3 , DateFormatDelegate ( 'dd/MM/yyyy' )) Much easier than I expected.","tags":"Tutorials","url":"https://overthere.co.uk/2012/07/29/using-qstyleditemdelegate-on-a-qtableview/","loc":"https://overthere.co.uk/2012/07/29/using-qstyleditemdelegate-on-a-qtableview/"},{"title":"Splitting old-style JPEG encoded TIFFs","text":"The tiffsplit program from the libtiff library does a good job of splitting multi-page TIFF files into single pages. It doesn't seem that great at handling TIFFs saved with ‘old-style' JPEG encoding. It'll produce files, and the correct number of files too, but the files are actually in JPEG format. Most image viewers won't open them still because they're JPEG files with TIFF headers. Assuming you have a TIFF file made up entirely of old-style JPEG encoded images you can loop through the files that tiffsplit has exported and remove the first eight bytes to give valid JPEG files. The Python function below will write the contents of a given file that come after the first eight bytes into a new file with the ‘ .jpg ' extension before deleting the original passed file. def remove_header ( path ): \"\"\" Write the contents of the given file after the first 8 bytes to a new file, then delete the original. \"\"\" new_path = ' %s .jpg' % os . path . splitext ( path )[ 0 ] with open ( path , 'rb' ) as input_file : with open ( new_path , 'wb' ) as output_file : input_file . seek ( 8 ) output_file . write ( input_file . read ()) os . remove ( path )","tags":"Blog","url":"https://overthere.co.uk/2012/05/18/splitting-old-style-jpeg-encoded-tiffs/","loc":"https://overthere.co.uk/2012/05/18/splitting-old-style-jpeg-encoded-tiffs/"},{"title":"Windows 7 Minimal Taskbar Menu","text":"Right clicking the taskbar in Windows 7 and selecting Toolbars and New Toolbar will let you select a folder on your computer to add as a taskbar menu. Here's how to make the label take up less space… When you create a new toolbar Windows will add the folder name as a label: I'd prefer it to not take up as much space. Wanting to create a menu for quick AutoHotkey scripts I started with a folder named, simply, ‘Scripts'. Too big. I thought maybe if I created a folder containing just a space character that would work. Then I'd just have a menu without a label - I don't really need a label anyway and I'm all for saving taskbar space. But no. Have you every tried creating a folder in Windows named just with the space character? It doesn't seem to work. It kept being named ‘New Folder' instead. Then I remembered an old trick. I can't even remember what it was for now, but I was using Windows 95 at the time so it was a while aog. I needed to put a space into something but the software I was using prevented it. I used a different character instead; the non-breaking space (Alt+0160 on the numerical keypad under Windows). I gave it a go and sure enough I was able to create a new folder with a seemingly blank character. So the menu now? Much nicer.","tags":"Blog","url":"https://overthere.co.uk/2011/10/20/windows-7-minimal-taskbar-menu/","loc":"https://overthere.co.uk/2011/10/20/windows-7-minimal-taskbar-menu/"},{"title":"Cleaning QR Codes","text":"At work we use QR Codes . It's a pretty recent thing. For a few clients we used to scan pages of a file and then have the scanner operator stop what they were doing to give the TIFF file a meaningful filename. Now we have the clients supply cover sheets, generated with custom software, that contain QR codes. These then get processed after scanning and before the scan of the header sheet is discarded the indexing data is decoded using ZBar through an AutoHotkey script. A few days ago we hit a problem. We'd scanned a few thousand pages but the script was unable to decode any of the indexing data from the QR codes. Not a single page. After looking into it I found that there were quality issues with the printing of the cover sheet. I could tell that the QR code was valid because the app I use on my mobile phone could read it fine, but ZBar could not. And ZBar is what matters – I wasn't about to sit down decoding QR codes with my phone all day. Here's one of the troublesome codes: After playing with the QR code image in Photoshop for a bit I found a way of making the code readable to ZBar. I still needed a way to process the image from within a script on the processing machines, for which we do not have a Photoshop license. GraphicsMagick to the rescue! Or ImageMagick , if that's your thing. The AutoHotkey script was modified so that if no data was returned when attempting to read the QR code it would run the image through an extra function outputting a ‘fixed' version of the image to a temporary file before reading that file instead and returning the data. The clean up used in GraphicsMagick is just: gm convert \"\" -blur 200 -level 80 \"\" The –blur and –level values can be tweaked depending on the quality of your image, but this worked perfectly for me in all the scanned images for the dodgy batch. Here's the cleaned QR code: Ok, so not actually that different to the original, but enough for ZBar to actually return data this time. If you're having trouble reading a QR code, or any other barcode using ZBar then give this a try. Seeing how the Windows binary for ZBar actually uses ImageMagick I'm hoping that eventually there'll be an auto-cleanup feature to deal with troublesome files in a later version.","tags":"Blog","url":"https://overthere.co.uk/2011/06/14/cleaning-qr-codes/","loc":"https://overthere.co.uk/2011/06/14/cleaning-qr-codes/"},{"title":"Installing Poppler for PyQt4 on Windows","text":"Poppler is a PDF rendering library based on the xpdf-3.0 code base. It has bindings for Qt4 which we can use through Python/PyQt. Using these libraries under most popular Linux distributions is as simple as installing the Poppler package, but under Windows I've found that things are a little more tricky to get working. At work, with the main business being document scanning, we deal with PDF files a lot. I've written a few custom applications that allow people to use the PDF files that we have supplied for them. Some of the applications simply launch the PDF in the user's default viewer when it is chosen from a list. Others use an embedded version of Adobe's Acrobat Reader which has to first be installed on the user's machine. Acrobat Reader doesn't play very well with apps written in PyQt in my experience. I don't really like the idea of having to use an entire program (and Acrobat Reader is a little hefty) embedded in my software just to view a file. Although I was able to load files into the embedded Acrobat Reader and adjust the display preferences I found that the application focus was left with Acrobat Reader after each change. For example, I connected a QSlider to some code to adjust the zoom of the document and all worked fine when using the mouse. Selecting the QSlider with the keyboard and attempting to use it didn't. Once the zoom had moved one step the focus would be taken from the QSlider and left with Acrobat Reader, meaning that further adjustments from the keyboard required the re-selecting of the QSlider . I tried to find a way around this. I failed. I went in search of an alternative to Acrobat Reader and found Poppler. Based on the xpdf-3.0 codebase and released under the GPL this seemed to be exactly what I needed. It would let me view PDF files in my PyQt application without having to use Acrobat Reader along with letting me perform a few other PDF related tasks. Great. I tried to get it to work on Windows. Oh, I tried. I'm not that experienced a programmer and don't know a great deal about compiling C code. I headed over to the Poppler mailing list and although there were a few people asking how they could use Poppler on Windows there were not that many answers. At least, nothing that I was able to follow. A few people seem to be searching for the term ‘ How to compile Poppler on Windows ', but there was nothing really that I could use. In my Ubuntu Linux installation I was able to use Poppler simply by installing the package. I wrote a quick test program to view a PDF and it worked great and was a lot faster than I expected at rendering the pages. Unfortunately at work I use Windows, as do pretty much all of our customers. A few months went by with a couple more failed attempts at getting things to work and then last week I actually managed it. It's cheating a little; I'm using the installer from the KDE Windows Initiative to help me along, but it works and gives me a usable Poppler library that I can use from within PyQt on Windows. This is by no means the only way and there are many projects that use Poppler on Windows quite successfully, but this is a fairly simple way to get things set up and working and I thought I should post a guide on how to do it. Download List First of all there are a few things that you will need to download. Python http://python.org/download/ Personally I'm still using version 2.x of Python. At the time of writing the most recent of this branch is 2.7.1, so click the link for ‘Python 2.7.1 Windows Installer' at the download link and install it if you don't already have Python set up on your machine. Qt SDK http://qt.nokia.com/downloads We don't have to compile all of Qt. We can get away with just downloading the SDK installer which gives us the files we need for the other things we'll be compiling. Choose LGPL from the download page and download the installer that at the time of writing is labelled ‘Qt SDK for Windows* (322 MB )‘. This gives me an install of Qt 4.7.0 (2010/05). SIP http://www.riverbankcomputing.co.uk/software/sip/download SIP is a set of bindings for using C/C++ libraries with Python. You'll need to have this compiled and installed before we build PyQt. The latest version for me right now is 4.12.1. Download the Windows Source archive. PyQt4 http://www.riverbankcomputing.co.uk/software/pyqt/download This is the package that performs the magical task of making Qt work with Python. There are binary files available that install the necessary Qt, SIP and PyQt4 files needed for normal PyQt4 tasks. These cannot be used if you want to use Poppler. The PyQt4 binaries for Windows available at the Riverbank Computing site are compiled using Microsoft Visual Studio. In order to use Poppler in PyQt4 on Windows we need to also compile pypoppler-qt4, which I'll be compiling with MinGW. For pypoppler-qt4 to work we need to first compile PyQt4 ourselves using MinGW to make things compatible. It may be possible to use the Microsoft Visual Studio compiler to compile pypoppler-qt4, but that's not something I have installed or have ever used. This is what caused a lot of my problems the first time I tried to get things working. The latest version of PyQt4 as I'm writing this is 4.8.3 and again you'll need to download the Windows source package. KDE http://windows.kde.org/ The KDE Windows Initiative has done the hard work of compiling Poppler (along with it's various dependencies) for us. To save us having to do the same thing we can just download the Windows installer and use it to grab the files we'll need to compile pypoppler-qt4. Choose Download Installer from the Download menu on the linked page. pypoppler-qt4 http://svn.pardus.org.tr/uludag/trunk/playground/pypoppler-qt4/ I've given the link here for the download location for the pypoppler-qt4 source, it's up to you whether you download this with a Subversion client or through your web browser. If using a web browser just download all the files one at a time. There aren't that many, just six at the time of writing including the license information and authors list. If you're downloading using a Subversion client we'll make a new folder called ‘src' on the root of the drive. Switch to it and issue the command for Subversion to download the source that we need. The steps for this in the command prompt are: cd c:\\ mkdir src cd src svn checkout http://svn.pardus.org.tr/uludag/trunk/playground/pypoppler-qt4/ If your Subversion client isn't in your path you'll need to type the full path to your svn binary. If using the Slik SVN client mentioned in the optional installs below this would mean replacing ‘svn' above with ‘C:\\Program Files\\SlikSvn\\bin\\svn.exe' if you installed the 32-bit version to the default folder. I wasn't able to get this to compile on Windows as it was but I had success with the configure.py file from the SlidePresenterView project's modifications. If you have Bazaar installed you can get the latest version by entering: bzr branch lp:~spv-dev/slidepresenterview/pypoppler-qt4 into your command prompt. Otherwise you can download the copy I used from here . Optional Downloads These aren't actually needed to get things working, but are recommended. pywin32 / Python for Windows extensions (optional) http://sourceforge.net/projects/pywin32/files/pywin32/Build%20214/ Not actually needed for this tutorial, but if you're using Python on a Windows machine it's a pretty good idea to have it and should be part of your standard install. I'm using the file labelled ‘pywin32-214.win32-py2.7.exe' to go with my Python 2.7.1 install. You'll need to download a different install if your version of Python differs. setuptools – (optional) http://pypi.python.org/pypi/setuptools Again, not actually needed for the tutorial but something that you should have anyway for easily installing PyPI packages along with their dependencies. The current version as of now is 0.6c11 – if you're using Python 2.7.x as described above go ahead and download the file marked ‘setuptools-0.6c11.win32-py2.7.exe', otherwise substitute for your setup. Slik SVN , or any Subversion client (optional) http://www.sliksvn.com/en/download It doesn't have to be slik subversion – any subversion client will do if you already have one installed. We'll need this to download the pypoppler-qt4 source, unless you want to just download the files manually through your web browser. It's a good idea to have a Subversion client installed though if you're going to play with new bits of software. I grabbed slik subversion 1.6.15. QScintilla2 http://www.riverbankcomputing.co.uk/static/Downloads/QScintilla2/QScintilla-gpl-2.4.6.zip A Qt port of the Scintilla C++ editor control. This is a required install if you also want to install Eric4. Eric4 http://sourceforge.net/projects/eric-ide/files/eric4/stable/4.4.12/eric4-4.4.12.zip/download My favourite IDE for writing PyQt applications on Windows and Linux. The current version at the time of writing is 4.4.12. You should now have all the files needed to work through this tutorial. Step 1 - Installing Python This should be nice and easy. If you're reading this tutorial then I'd imagine you're a Python user with Python installed already. If not, just run the installer and follow the instructions. Although not needed directly for this tutorial I'd recommend installing pywin32 and setuptools as well at this point. Step 2 - Installing Qt SDK Another easy one. Again, just run the installer and follow the instructions if you don't already have the Qt SDK installed. You also need to add a few folders to your system's path environment. This is something that has had me screaming ‘ WHY ?!' at my screen quite a bit – it turns out that the order that these folders appear in your list are quite important. On my machine the three folders that needed adding (and in this order too) were: C : \\Qt\\2010.05\\qt C : \\Qt\\2010.05\\bin C : \\Qt\\2010.05\\qt\\bin To add these to your system path, right click on My Computer on the desktop (or the ‘ Computer ' entry in the Start Menu) and choose ‘Properties', followed by ‘Advanced System Settings' from the menu on the left of the new window that appears. Typing ‘ sysdm.cpl ' in the Run Dialog and clicking the Advanced tab will also get you here. Click the Environment Variables button at the bottom of the window and then from ‘System variables' highlight ‘Path' and click the Edit button. Enter these three paths (or the versions of them that match the setup on your machine) into the ‘ Variable value ' box and separate them by a semicolon. Make sure they're the first items in there and that you include a semicolon after all three folder paths so that your existing items are separated out. Step 3 - Installing SIP First of all you must unzip your sip archive to a folder on your hard drive. I'll be keeping all of my source code for this tutorial in a folder called ‘ src ' at the root of my C drive. Using a folder without spaces and close to the root of your drive just makes things a little easier when we're working with a command prompt. The Qt SDK , along with the header files we need for our building, installs a copy of the MinGW compiler. I ran into a few problems with folders in my Windows system path conflicting with the files from the Qt SDK before finally finding out that the Qt SDK provides a batch file that opens a command prompt and, inside it, clears your system's path variable and sets a few other variables needed for our compiling. This console can be started by clicking Start –> All Programs –> Qt SDK by Nokia v2010.05 (open source) –> Qt Command Prompt . Switch to the folder containing your SIP source code. You may normally start Python scripts in Windows by either directly running the ‘ .py ' file or by typing ‘python' followed by the name of your file in a command prompt. You don't need the full path because the Python installer adds the python.exe to your system path. Since we're in Qt's customised terminal Python is no longer in our path (at least, not in this command prompt instance) so we must call the python.exe using it's full path, changing it if your version differs from mine. Run the configure script through Python passing it the ‘ -p win32-g++ ' argument: cd \\src\\sip-4.12.1 c : \\Python27\\python.exe configure.py -p win32-g++ You should see some text scroll through the window ending in ‘Creating sip module Makefile…'. Once done type two more commands to build and then install SIP : mingw32-make mingw32-make install SIP should now be installed and your command prompt should look something like this: Step 4 - Installing PyQt4 This is pretty similar to installing SIP . I'm using the commercial version of PyQt4, but this should work the same for the GPL version. Unzip your PyQt4 source to c:\\src and if you're using the commercial version you must also add your pyqt-commercial.sip file (available from your account page on the Riverbank site) in the ‘ sip ' folder within your PyQt4 source folder (‘ C:\\src\\PyQt-win-commercial-4.8.3\\sip ' in my case). In the Qt command prompt that you have left over from installing SIP switch to your PyQt4 source folder and run PyQt4's configure script through Python with the ‘ -w ' switch. cd \\src\\PyQt-win-commercial-4.8.3 c : \\Python27\\python.exe configure.py –w If asked to accept the license type ‘ yes ' followed by the enter key to proceed. After a couple of minutes this ends with the text ‘ Creating pyqtconfig.py… ' on my machine. As with SIP we now compile the source by entering: mingw32-make mingw32-make install This should take a few minutes to complete and your console window should look something like this when finished. We just need to check that everything installed ok and that we can actually import and use PyQt. Open up a new Python terminal ( IDLE is fine, or you could just use the console window you already have open) and type the following: from PyQt4.Qt import * from sip import * print [ SIP_VERSION_STR , QT_VERSION_STR , PYQT_VERSION_STR ] This should return: [ '4.12.1' , '4.7.0' , '4.8.3' ] or whatever versions of SIP , Qt and PyQt respectively that you installed. So long as you get numbers and not an error you should be ok. Step 5 - Installing Poppler (via KDE Installer) So here's the bit where we cheat a little (thanks, KDE !). Run the installer and select the option ‘ Install from Internet '. I've set the install path on my machine to ‘ c:\\kde '. When asked about the Install Mode choose ‘ Package Manager ' and ‘ MinGW4 W32 '. I went with the download server ‘ Central Europe, Germany (http://www.winkde.org) ' after trying a few that were a little closer to me but didn't have the latest KDE version. Once you've chosen the latest version you'll want to download the following packages: poppler-mingw: Bin and Devel version poppler-data: Bin version freetype-mingw: Bin version jpeg: Bin version libpng: Bin version libxml2: Bin version iconv: Bin version zlib: Bin version Once these are selected hit ‘ Next ' then ‘ Finish ' to install. Once installed we need to add the KDE ‘ bin ' folder (‘ c:\\kde\\bin ' in my install – adjust this if you installed KDE to a different folder) to the system path like we did for Qt in Step 2 and then we're done. Step 6 - Installing pypoppler-qt4 You should already have the pypoppler-qt4 source checked out of SVN from the download list at the top of this tutorial. If not, go back and do that now. Next, download this version of the configure.py file and replace the version from your SVN checkout with it. This will allow us to specify where our Poppler libraries (thank you again, KDE Installer) are with this command (all on one line): c : \\Python27\\python.exe configure.py --popplerqt-includes-dir ^ c:\\kde\\include\\poppler --popplerqt-libs-dir c:\\kde\\bin The configure script should then tell you where it will be installing it's files: Using PopplerQt include paths: ['c:\\\\kde\\\\include\\\\poppler'] Using PopplerQt libraries paths: ['c:\\\\kde\\\\bin'] Configured to install SIP in c:\\Python27\\sip Configured to install binaries in c:\\Python27\\Lib\\site-packages If the paths look correct and match what you passed the configure.py script then go ahead and run: mingw32-make mingw32-make install When complete your command prompt should look something like this: Step 7 - Installing other optional files. I swear by using eric4 for developing in PyQt. It's a decent IDE and integrates well with the PyQt stuff allowing you auto compile any changed GUI elements automatically when running your project along with providing UIs for generating code for interface components and lots of other nice things. It also depends on QScintilla for displaying code. This is something that comes standard with the PyQt4 setup binaries for Windows but we're installing from source so if you need QScintilla you'll need to compile that too. Unpack the source archive into c:\\src as with our other source packages. Once again in the Qt command prompt type the following from the QScintilla source folder: cd Qt4 qmake qscintilla.pro mingw32-make mingw32-make install Once installed you'll need to copy the qscintilla2.dll file from your Qt Lib folder to your Qt Bin folder. copy c:\\Qt\\2010.05\\qt\\lib\\qscintilla2.dll c:\\Qt\\2010.05\\qt\\bin And finally we compile the Python wrappers. Switch back to the root of your QScintilla source folder and then switch into the Python folder (replace for the path to your QScintilla source folder if needed): cd C:\\src\\QScintilla-commercial-2.4.6\\Python c : \\Python27\\python.exe configure.py mingw32-make mingw32-make install To install eric4 you'll just need to unpack the zip archive and execute: c : \\Python27\\python.exe install.py from within the unpacked folder. Eric4 can be started by running the eric4.bat file that has been created in your Python folder. Testing - Making sure it all works. Now that everything is installed it's time to see if it all works. Make sure you have a PDF file somewhere on your computer for testing and fire up a Python interpreter. import QtPoppler doc = QtPoppler . Poppler . Document . load ( 'c:/test/test.pdf' ) doc . numPages () This should return the number of pages in your PDF file. For my PDF it returned a count of 641 pages: If QtPoppler imported without any errors and returned a pagecount after calling numPages() on a loaded document then everything is working. To jump in and start doing things with PDF pages you can render them to a QImage and display however you would normally display a QImage in your program: doc . page ( 0 ) . renderToImage () Specify your page number as a parameter to doc.page() – page numbers start from zero. For more information refer to the Poppler Qt4 documentation .","tags":"Tutorials","url":"https://overthere.co.uk/2011/03/06/setup-poppler-windows-pyqt/","loc":"https://overthere.co.uk/2011/03/06/setup-poppler-windows-pyqt/"},{"title":"Native Desktop Application for Subsonic","text":"I've been looking for a new personal project to work on for a while and I've been having trouble finding something. I wanted something that I'd use myself, otherwise my interest would quickly drop. Something that ideally I would use every day. I also wanted to write something that other people would find a use for as well. And it had to be written in Python and be something completely different to anything I've played with before. So I've decided to write a desktop client for Subsonic . This project is dead. Well, it didn't make it much further than what is mentioned in this post. Take a look at this for a similar project whose aims are similar to what I was talking about in this post. A few weeks ago I had a play around with Spotify . It's a really good service, but a little too pricey and while the desktop application is quite good I found the Android application to be a bit laggy. They have a wide variety of music but with some notable omissions (no Pink Floyd or AC / DC ). I cancelled my subscription before my first month had ended. Last.fm is an old favourite of mine for streaming music. They have just removed the feature I used the most though: the streaming of Loved Tracks. While Last.fm is still good for streaming random music that is a mix of stuff that I like and stuff that I've not heard before but would probably like, I miss having control of my playlist. I tried Grroveshark – much, much better price wise than Spotify and with an Android application that seems to work a lot better. They provide a desktop application written in Adobe Air which is fine but I found that a lot of the music was not labelled correctly. It's annoying to build a playlist and then have a totally different song to what you expected play. I still use Grooveshark through their website occasionally and may even re-new my VIP membership in the future with the price being so low. Subsonic works differently than all of these. The music is streamed from your own server. This gets around the lack of Pink Floyd quite nicely and for a one time donation that is comparable to a single month's subscription to Spotify you can keep all features active after your 30 day trial. Music can be streamed either through a web browser, an Adobe Air client or a very well made Android client. So far this has worked out the best for me. Subsonic is also open source and has an open API . While the Adobe Air client is functional it doesn't really do much more than play music. Seeing how I've not used Python/ QT to do anything with audio files yet or talk to web services / parse XML files I thought it would be a fun project to work on a desktop client. Writing it in PyQt means that it should run on Windows as well as Linux and OS X. My plan is to integrate my client with Last.fm as well to provide dynamic playlist support (add one track and have the player automatically add similar tracks while playing), artist information and the old Loved Tracks feature that Last.fm used to provide. It's going to take a while and will be something I just work on in my free time. So far I'm able to pull a list of artists along with album and track information complete with cover art. Here's a screenshot of how things are looking right now: Of course, the look is going to change quite a bit and I'm sure I'll be thinking of new things to add as I'm working on it. There are quite a few features that could be added – local music support rather than just being limited to Subsonic, Last.fm streaming rather than just pulling track details and cross referencing them with the Subsonic library and many other things. It's good to have finally found something I'll enjoy building and will use myself quite often. Also, I need a name for it. I can't think of anything right now. Suggestions?","tags":"Blog","url":"https://overthere.co.uk/2010/12/08/native-desktop-application-for-subsonic/","loc":"https://overthere.co.uk/2010/12/08/native-desktop-application-for-subsonic/"}]};