All posts by Dominik

Dominik is a PhD student at the Control Theory and Robotics Lab, TU Darmstadt, as part of the Research Training Group GKMM (GRK1362). My research focuses on state estimation in distributed systems. As hobby, I contribute to the KDE project and work on the Kate application and editor component.

How to convert pdf to svg

In a project I’m currently working on I need to display the result of TeX code. So I thought it would be nice and accurate to compile the TeX code to produce a pdf, and then use libpoppler-qt4 to draw the pdf. This works in principal, but there is a licensing problem: libpoppler is GPL, and I want to use it in a LGPL library.

So I searched the net and found dvipng, which converts a dvi file to png. It even supports transparent backgrounds. So I could convert the dvi file to png through QProcess+dvipng, and then display the png file. This works, but whenever you scale the canvas the result looks ugly since png is not a vector graphic.

Next, I found pdf2svg that converts a pdf file into the scalable vector graphics format svg. In theory, I then can use QSvgRenderer to load and render the SVG on-the-fly using QSvgRenderer::render(QPainter*, …). So I first tested to convert the pdf to svg with this tool and then view it in InkScape. The result was perfect: InkScape renders the svg file exactly like Okular renders the pdf file:

So I looked into the source code of pdf2svg and saw that it uses libpoppler with Cairo. This reflects an additional dependency on cairo, so I went ahead and converted the cairo based code to Qt, using libpopper-qt4. The code basically boils down to:

// create poppler pdf document
Poppler::Document *document = Poppler::Document::load(args[1]);
document->setRenderBackend(Poppler::Document::ArthurBackend);
document->setRenderHint(Poppler::Document::Antialiasing, true);
document->setRenderHint(Poppler::Document::TextAntialiasing, true);
document->setRenderHint(Poppler::Document::TextHinting, true);
document->setRenderHint(Poppler::Document::TextSlightHinting, true);
document->setPaperColor(Qt::transparent);
// prepare QSvgGenerator as QPaintDevice
QSvgGenerator svgGenerator;
svgGenerator.setResolution(72); // resolution in dpi
svgGenerator.setFileName("out.svg");
svgGenerator.setSize(document->page(0)->pageSize());

// perform painting
QPainter painter(&svgGenerator);
document->page(0)->renderToPainter(&painter);
painter.end();

This code does indeed generate the svg code for the pdf file. However, the result is surprisingly ugly and wrong:

First, the pen seems too thick, and second the character ‘d’ is wrong on the left. I’ve tried changing the resolution (setResolution()) and also the page size (setSize()) of QSvgGenerator, always getting the same result. Searching the net reveals that QSvgGenerator seems to have quite some glitches with respect to WYSIWYG rendering. I tried to use QSvgGenerator before in 2009 and came out with unusable results. Maybe I’m missing something?

Update 1: It’s not QSvgGenerator that is to blame here. It’s indeed the Arthur backend of libpoppler. I send a patch to the poppler developers that fixes the issue with too bold glyphs. The pahts are still too inaccurate, though.

Update2: Using dvisvgm with the option –no-fonts results in an SVG file that QSvgRenderer renders correctly. So this is the current solution to get a TeX document rendered via SVG in Qt.

Kate: Search & Replace Notifications in KDE 4.11

In KDE 4.10, the “Find All” and “Replace All” highlights all matches and at the same time shows a passive notification in a bar below the view. This bar is animated, and takes quite a lot of place in addition to the search & replace bar.

Since some days, Kate Part can also show passive notifications floating in the view. Hence, we’ve changed the passive notification to appear on the bottom right as a small info message, showing the number of matches. However, in order to make this passive notification as small as possible, we removed the “Close” button, since the notification is hidden after 3 seconds anyway. Further, we removed the “Keep Highlighting” button. If you want to keep the highlights, just do not close the search & replace bar. The following video demonstrates this behavior, first for KDE 4.10, then how it currently will be in KDE 4.11 (watch the video in 720p):

Kate: New contributors, Valgrind, and a fixed bug

In the recent months Kate saw quite some contributions from developers other than “the usual kate developers”. This is really cool, areas include more work on python plugins, a lot of bug fixing and fine tuning in the vi input mode, an improved python indenter, and more unit tests. Especially one unit test turned out to be immensely useful and resulted in a fix for the infamous “rangesForLine” crash (about 40 times reported). We even decided to backport this to KDE 4.10.2, so KDevelopers and Kile LaTeXers please keep an eye open on whether this has any side effects!

Basically, the unit test provided us with a valgrind trace. Since valgrind is a very useful tool for all developers, we’ll have a closer look at the valgrind trace:

==10276== Invalid read of size 4
==10276== at 0x62F2116: Kate::TextCursor::lineInternal() const (katetextcursor.h:134)
==10276== by 0x62F9035: Kate::TextBlock::updateRange(Kate::TextRange*) (katetextblock.cpp:572)
==10276== by 0x62F8C57: Kate::TextBlock::mergeBlock(Kate::TextBlock*) (katetextblock.cpp:522)
==10276== by 0x62EFAA1: Kate::TextBuffer::balanceBlock(int) (katetextbuffer.cpp:494)
==10276== by 0x62EF1B2: Kate::TextBuffer::unwrapLine(int) (katetextbuffer.cpp:298)
==10276== by 0x637BB9C: KateBuffer::unwrapLines(int, int) (katebuffer.cpp:292)
==10276== by 0x6359DE9: KateDocument::editRemoveLines(int, int) (katedocument.cpp:1321)
==10276== by 0x6359AD6: KateDocument::editRemoveLine(int) (katedocument.cpp:1293)
==10276== by 0×6357841: KateDocument::removeLine(int) (katedocument.cpp:732)
==10276== by 0x6394C6A: KateScriptDocument::removeLine(int) (katescriptdocument.cpp:513)
==10276== Address 0×14353470 is 96 bytes inside a block of size 152 free’d
==10276== at 0x4C2A44B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10276== by 0x62FDE4D: Kate::TextRange::~TextRange() (katetextrange.cpp:66)
==10276== by 0x6470B1E: KateOnTheFlyChecker::deleteMovingRange(KTextEditor::MovingRange*) (ontheflycheck.cpp:535)
==10276== by 0×6470657: KateOnTheFlyChecker::rangeEmpty(KTextEditor::MovingRange*) (ontheflycheck.cpp:489)
==10276== by 0x62FE641: Kate::TextRange::checkValidity(int, int, bool) (katetextrange.cpp:196)
==10276== by 0x62F6C84: Kate::TextBlock::wrapLine(KTextEditor::Cursor const&) (katetextblock.cpp:168)
==10276== by 0x62EEF1D: Kate::TextBuffer::wrapLine(KTextEditor::Cursor const&) (katetextbuffer.cpp:231)
==10276== by 0x637BA6D: KateBuffer::wrapLine(KTextEditor::Cursor const&) (katebuffer.cpp:275)
==10276== by 0x635972E: KateDocument::editInsertLine(int, QString const&) (katedocument.cpp:1246)
==10276== by 0×6357690: KateDocument::insertLine(int, QString const&) (katedocument.cpp:706)
==10276== by 0x6394C32: KateScriptDocument::insertLine(int, QString const&) (katescriptdocument.cpp:508)

The trace tells us that somewhere in TextCursor::lineIntern() we read a variable/address that is invalid. In fact, we are reading a pointer called m_block that should be valid. In this case, as we know the pointer should be valid, we can conclude that the entire TextCursor object is then corrupted/invalid. Since the cursor is part of a TextRange, it means the TextRange is already invalid. Interestingly, this is exactly what valgrind is telling us in the lower part: The TextRange destructor that lead to the invalid read above is called in the 2nd half of the valgrind trace. From this, we can conclude that the function KateTextBuffer::mergeBlock() accesses a dangling pointer to a TextRange.

That’s a good start, but in fact, this is where the hard work begins. I’ve invesed about 2 hours to find that probably the dangling pointer is in a cache that is supposed to make the access of the TextRanges (MovingRanges to be precise) faster. Christoph then looked into it and tried several attempts to fix the nasty bug, finally showing us that the cache was indeed wrong but due to a too-late fixup of the start/end text cursors with respect to the TextBlocks. In total, Christoph probably invested about 6 hours, and given that Gerald certainly took quite a lot of time too to write the unit test, we probably have more than 10 ours just to get this bug fixed. Still, the good news is that we got it! And if we are lucky, this was the last bug in  Kate’s text buffer. So on to the next crashes… Help welcome!

Navigation in Okular: Back & Forward

Okular, KDE’s universal document viewer, has a really cool feature I’m using for years already: “Go > Forward” and “Go > Backward”. These two actions allow to quickly jump to positions in the document where you came from in a chronological order. Consider e.g. reading the phrase “As shown in [15], …”, and you want to know quickly lookup reference [15]. So you click on it, and okular will jump to the list of references. And “Go > Back” will bring you back to exactly the position where you came from.

Awesome :-D

In fact, I removed the “Previous” and “Next”-page buttons from the toolbar in favor of the “Back” and “Forward” feature, which is much more useful to me :) Given that my colleagues were not aware of this feature (all experts in LaTeX  and all using Kile and Okular), I thought to praise it here in a dedicated blog. Interestingly, the Okular Handbook is missing this feature. Any takers to fix this? :-) Update: This is also mentioned in the Okular handbook :-)