Saturday, 3 February 2018

svg inkscape and ghostscript...

Very technical one this time.

As I have blogged before, a lot of things are now being created as a master in SVG format. It's one failing is blocks of wrapped text, but apart from that it works really well.

So, the new FireBrick serial number labels are done in SVG, and they include a QR code of the serial number. Simples. Well, you would think.

The target printer is 300dpi, and so the design has all been done on nice hard integer units at 300dpi. This is especially important for things like bar codes which need to be pixel aligned. In this case 4 prints pixels wide per QR pixel. If this is not perfectly scaled or aligned the QR code gets all aliased in nasty ways and is not as readable.

The svg uses width/height and viewPort to ensure we can use 300dpi units but be the right size, e.g. height="27.940000mm" viewBox="0 0 1185 330" width="100.330000mm"

The SVG looks perfect, obviously, whatever scale...

I can use inkscape to convert that to a png at 300dpi and it looks perfect...

We are using a Brother QL-700 which installs nicely on (32 bit) linux using the provided drivers and operates like a normal Linux printer as postscript (using ghostscript behind the scenes). So I use inkscape to make an EPS for printing. Again, simple.

This is where it goes wrong. inkscape is making postscript using default (72 dpi) units and 3 decimal places. e.g.  28.801 28.16 m 35.52 28.16 l which means a gap there of 6.719 pt which is 27.995 pixels at 300dpi, that is 7 QR code pixels. The issue is rounding. Sometimes it would be 3.995 pixels and sometimes 4.005 and so on, so you end up with a badly aliased QR code.

The fix was to make the SVG not scaled to the right size but just using the 300 dpi units. In fact, better would have been to scale to 72 dpi units default for EPS but as it happens the default units of SVG (96 dpi) work to produce integer values. This, of course, makes a much bigger image, so a bit of sed to add a 96 300 div dup scale was all that was needed.

What an annoying mess. If only inkscape understood that EPS can have a scale command, and it could have maintained the original units from the SVG in the EPS rather than converting to 3 decimal places. I may find the developer forum and suggest a change!

Here are the before and after - the bottom is before which as you can see from the checker board is rather broken. Now we have nice readable QR codes, yay!


  1. If you have occasion to use PostScript rather than SVG in future you might be interested in the "gridfit" logic in a branch of my generator:

    During the RIP it probes the resolution of the device space (or uses a given value), scales the barcode pitch to the nearest integer multiple of the device pixel size and aligns the base point to the centre of a pixel. This eliminates pixel grazing resulting in an unaliased image.

    1. Been there, done that, years ago for barcodes in postscript - much easier than SVG for such things :-)