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); 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.