API work
While working on oKular I faced or was asked to consider a list of things the file format handling generator/backend might need. First problem was search, kpdf when branched did not have a page abstraction class, it did not handle searches between the lines too, it could only search for words on the same line.
Page abstraction
So the first thing I wrote was the page abstraction class, which holds a vector of text entities and implements the search functions. Text entities are a character or a set of them with a rectangle box describing a normalized ([0;1] coordinates) position on the screen. The text entity class has also information about whether new line follows this entity (used for getting the text for given coordinates) and the standard rotation and baseline data. The search algorithm is quite fast and includes a simplifying function when returning a result.
The result is a regular area, which is a finite set of normalized rectangles that describe positions of the found words. The great thing about it is being a template which can be used for virtually anyobject, or even for regular areas if we need regular areas of different shapes! Don't you just love object oriented coding ?
Information pushing
How should the file format backend inform the program about an error? Or maybe it would want to display a message or a warning. It is a simple as emitting a signal now! The user can configure whether he wants the messages displayed using kpdf's supreme popups in the page view or a standard KDE message/error/warning box (the latter not included in beta1).
Settings
Support for generator settings is easy when you think about allowing to set settings only when the generator is loaded with the document, but what about allowing to configure all backends at all time? The solution was simpler then I thought but at a cost. All the generators that have settings support are loaded if user chooses to configure them, later if the user opens a filetype and a generator for it is already loaded, its not loaded again - just reused. Who would have thought it would be that easy.
Adding pages to the configuration dialog is done by the generator in Generator::addPage(KConfigDialog *).
Intercepting the event of the page and adding components to the GUI
The need for a possibility to intercept the events, such as a right mouse click, in the page view was reported by Wilfred Huss of kviewshell. To be generous, I am allowing the generator to intercept nearly all events page view receives, just reimplement the bool Generator::handleEvent(QEvent *) function! Return true if the page view should parse the event itself after your function finishes.
Adding components to the GUI was another important aspect, the most important GUI items in kpdf are the QToolBox in the navigation pane and the menu. You can specify an XML menu layout that is to be merged with the standard menu by subclassing the newly added getXMLFile function, while the QToolBox and KActionCollection objects are available to the generator in setupGUI (QToolbox*,KActionCollection *).
The Ghostscript generator for Postscript
The next deliverable I pointed in the SoC proposition for Google was a backend using Ghostscript. I admit taiming Ghostscript library (libgs) was hell. A partially documented API along side with some typos (like sending void** instead of void*) and the library having a C object API made it really no fun. But with help of ghostscript developers (great thanks to ghostgum of #ghostscript, the author of the API) I managed to understand how it works and wrote a perfectly good wrapping class. The road was harsh though, as ghostgum lives in Australia and I live in Poland, so it usually ment to me no sleep at night if I needed to talk to him.
Asynchronous renderer
The asynchronous renderer based on ghostscript is the first fully synchronous generator in kpdf. libgs was not thread aware and did not allow more then one instance in the generator, reusing the synchronous renderer was too slow for me to accept so I wrote a helper application that uses the wrapper class to generate a pixmap and uses X11 functions so do an ultra fast transmission of the QPixmap. The asynchronous renderer is a masterpiece, the wrapper around it includes even asynchronous killing of the no longer used instances of helper apps. I'm proud of it.
Finally one night i managed to overcome the problems.
- 18:27 30th of July - The libgs wrapper works, does not receive the pixmap properly from Ghostscript
- 03:27 31st of July - Broken receiving after enabling alpha channel, disabling it.
- 05:00 31st of July - First close attempt after understanding the format of the pixmap.
- 31st of July - Second attempt with the alpha channel being broken.
- 14:00 31st of July - First correct attempt, third times the charm.
- 18:00 31st of July - Working synchronous generator without antialiasing.
- 19:00 31st of July - Working synchronous generator without antialiasing.
- 19:00 13th of July - A screenshot of a fully working asynchronous and sychronous generators with antialiasing and Ghostscript message window.
Replacing kghostview
oKular is now a full replacement of kghostview without support for PDF files, which is easy enough to implement later. The replacement in KDE4 will close 90% of kghostview bugs, which kpdf implemented earlier like review support or better navigation panel.
No text search support
Unfortunately there is no currently available solution for postscript searching, pstotext handles only some PostScript files and does not work with anything other then latin1. Also note there is no such thing as encoding in PostScript, it uses a set of glyphs and when more are needed the unneeded ones are removed and new ones are added, locally on page, so the encoding migh change several times inside a document. Currently there is no sane possibility to work this out.
Ghostscript library
To use the Ghostscript generator you need a Ghostscript compiled with shared library. To do it manually, take the sources and after configuring do:
make so
and to install
make soinstall
A list of RPMS with libgs can be found here. Debian does not currently provide any package with libgs.
Make sure you have it in your library path because using the --with-gs-library switch does not work yet (no idea how to add it to the list of directories checked by KDE_CHECK_LIB).
oKular Beta 1 "monoKle"
I am releasing oKular SVN revision as beta 1. It should work correctly with PostScript, Image and PDF files. For now my working version includes CHM support I did not put in this beta, due to some pagesize calculation problems. The CHM support is based on the chmlib wrapping code from kchmpart (three files actually), I did a few changes to make it usable in oKular, wrote the code that uses khtml to render the compressed html pages myself. Beta 2 is planned for mid October, when I have most of the kviewshell plugins ported to oKular. So get: the tarball for oKular beta1 'monoKle' Do not report this to slashdot. If the server gets slashdotted, there will be no betas and you'll have to wait until KDE4.