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.

10 thoughts on “How to convert pdf to svg”

  1. This is indeed a bug/limitation in the poppler Arthur backend. You can easily test this by rendering to a QPicture first and then using the QPicture as source for QPainter. You’ll see the same ugly pen width.

    1. Right, in discussion with Albert I looked into the Arthur backend of libpoppler and was able to fix the issue that the text is rendered too bold. But the other issue remains: The glyphs are represented as QPainterPaths, and the QPainterPaths somehow are incorrect. This maybe be non-trivial to fix, unfortunately. Still, it’s not QSvgGenerator that is to blame here.

  2. The SVG rendering has some limitations too, although I don’t think that comes into play here. It can’t do effects. The SVG renderer in QtWebkit is a bit better, but still not what I’d use — not even for simple previews. It has serious problems with scaling the images and effect parameters.

    If you don’t need effects, take a look: https://github.com/peterix/MultiMC5/blob/master/gui/iconcache.cpp

    I’ll eventually replace the svg rendering with something reliable — either a real SVG rendering library or plain old raster images exported from inkscape ~_~

    1. That’s also an option I’ve been pondering. Still, using a web renderer to only display a pdf looks overkill. I will probably end up using dvipng and rerun this with the correct dpi resolution. Ugly but effective enough, given all the quirks needed to get the pdf or svg version running. Sad :)

  3. I’m afraid I’m not much help for the question as asked, but have you considered using DVI output from TeX? There are direct DVI display tools, or converters to most conceivable formats. Licenses should be very liberal, given the era DVI was widely used.

    1. Yes, dvipng already delivers what I want. I display the result in a QGraphicsView, and this View can be zoomed.
      As soon as I zoom, I get aliasing effects of course, so I need to recreate the png with the correct dpi number. This is also the reason why I wanted to render pdf myself, and as other way to use svg.

      Is there another way to render DVI in my app myself so it also scales nicely?

      1. I have little experience in the subject and zero experience programming qt applications. The only other thing that comes to mind is ghostscript, but it’s unique license might be troublesome. A bit of googling that you might not have seen is http://qt-project.org/wiki/Qt_and_LaTeX_via_KLFBackend . Assuming it works well, the trouble I see with it is output to bitmap. Toward the end, I see a note that it can output SVG, but using ghostscript as an engine. I enjoy the subject, but sorry I can’t be of more help!

Leave a Reply