Show Your Working: Forcing Linux to print at actual size
19 May 2023

One day I decided I've had enough of computers and wanted to do literally anything else. Specifically, in that moment I wanted to print out some sewing patterns. Here is a 100mm test square I printed on my printer. Except it's only 94mm. 94mm!!!
Not going to lie, searching the internet for useful information has become real bleak lately. There's plenty of advice floating around to "Open the PDF in Acrobat and select "Actual size" when printing", but no advice about the Linux equivalent. To be honest the coward's way out would be to dig out the sacrificial Windows laptop, find a print driver and use Acrobat Reader, but I figured other people might like to know how to fix it, so here you go!
In order to figure out what's going on, let's have a bit of a recap of the Linux printing stack and the problem space in general. Printing under Linux is handled by CUPS, a userspace daemon responsible for connecting to printer hardware and feeding it the right slurry of bits. In this context, a printer "driver" is a PrinterName.ppd file (PostScript Printer Description), containing a bunch of information about the hardware, what features are supported, what slurry types to feed it, and so forth. Seperate to that, there is a printers.conf file listing each active printer and how it is connected; locally (LPT, USB) or via the network (IPP, JetDirect, SMB).
Now for the longest time, all of this configuration was manual. There were large collections of PPDs (such as foomatic) containing definitions for thousands of different printer models, usually not the one in front of you. More often than not you'd have to settle for one of the generic drivers, which produce a slurry that a lot of printers eat such as PCL6. If you're really unlucky the printer would need a proprietary driver; this would take the form of a PPD file plus a binary blob executable responsible for generating special Brand-Name Printer Slurry.
But here we are, with the Dark Age of Printing long behind us. In 2013 the Printer Working Group developed the IPP Everywhere standard, which Apple (amongst others) decided was the future for printing from mobile devices, and so has become a standard for consumer printers. Finally, network printers could enunciate exactly the type of slurry they would like and remove the need for drivers once and for all! You no longer had to suffer like your printing ancestors did.
Or so the theory goes. The printer I'm using is a Fuji Xerox DocuPrint P265 over IPP. For printing I'm using lpr, the CUPS-provided tool for sending files to the print spooler, with print-scaling set to none. In this scaling mode, content should be centered to fit on the page, with no resizing. This means e.g. an A4 sized document printed on A4 paper should be perfectly to scale and have about 5mm chopped off by the hardware page margins. When printing from an application such as Evince, the correct setting for "actual size" printing is Page Handling -> Page Scaling -> None.
First I tried printing a PDF with a document size of exactly 100mm x 100mm.
$ lpr 100mm.pdf -o print-scaling=none
The result was a square in the center of the page with a 94mm edge.
I tried printing another PDF in A4 with a box at the edge of the page, along with a 100mm square in the center. This produced an interesting tell; the square printed with a 94mm edge, but the page box showed up too! This implies that something was flat-out ignoring the page margin of the printer hardware. And yet surely the IPP standard would account for that!
After a bit more digging I discovered the driverless command bundled with CUPS, which connects to an IPP printer and generates a PPD file:
$ driverless ipp://192.168.1.2/ipp/print
*PPD-Adobe: "4.3"
*FormatVersion: "4.3"
*FileVersion: "1.28.17"
*LanguageVersion: English
*LanguageEncoding: ISOLatin1
*PSVersion: "(3010.000) 0"
*LanguageLevel: "3"
*FileSystem: False
*PCFileName: "drvless.ppd"
*Manufacturer: "FX"
*ModelName: "FX DocuPrint P265 dw"
*Product: "(FX DocuPrint P265 dw)"
*NickName: "FX DocuPrint P265 dw, driverless, cups-filters 1.28.17"
...
This all looks very sensible, let's see what it has to say about paper dimensions.
*DefaultPageSize: A4
*PageSize A4/A4: "<</PageSize[595.275590551181 841.889763779528]>>setpagedevice"
*DefaultPageRegion: A4
*PageRegion A4/A4: "<</PageSize[595.275590551181 841.889763779528]>>setpagedevice"
*DefaultImageableArea: A4
*ImageableArea A4: "12.245669291339 12.245669291339 583.029921259842 829.644094488189"
*DefaultPaperDimension: A4
*PaperDimension A4: "595.275590551181 841.889763779528"
Yep, there's a margin. It's in weird printer units but there's definitely about 5mm carved out from the edge of the full page. What gives?
Oh wait, CUPS makes its own cache of the PPD doesn't it. Maybe mine is slightly di
$ cat /etc/cups/ppd/FujiXerox.ppd
*PPD-Adobe: "4.3"
*%%%% PPD file for Generic IPP Everywhere Printer with CUPS.
*%%%% Created by the CUPS PPD Compiler CUPS v2.3.3op2.
*% (c) 2014 OpenPrinting
*FormatVersion: "4.3"
*FileVersion: "1.0"
*LanguageVersion: English
*LanguageEncoding: ISOLatin1
*PCFileName: "pwgrast.ppd"
*Product: "(Generic IPP Everywhere Printer)"
*Manufacturer: "Generic"
*ModelName: "Generic IPP Everywhere Printer"
*ShortNickName: "Generic IPP Everywhere Printer"
*NickName: "Generic IPP Everywhere Printer"
*PSVersion: "(3010.000) 0"
Oh. Oh no.
*DefaultPageSize: A4
*PageSize A4/A4: "<</PageSize[595.28 841.89]/ImagingBBox null>>setpagedevice"
*DefaultPageRegion: A4
*PageRegion A4/A4: "<</PageSize[595.28 841.89]/ImagingBBox null>>setpagedevice"
*DefaultImageableArea: A4
*ImageableArea A4/A4: "0 0 595.280029296875 841.890014648438"
*DefaultPaperDimension: A4
*PaperDimension A4/A4: "595.280029296875 841.890014648438"
The short version is that (CUPS/GNOME Settings/whatever I used to set it up) has gone down some other, more sinister route to create a PPD file for my driverless printer. One which doesn't involve page margins. But it does have about four times as many exotic media types, on the offchance that I might need to print a swan.
$ sudo su
$ cd /etc/cups/ppd
$ systemctl stop cups
$ mv FujiXerox.ppd FujiXerox.ppd.bak
$ driverless ipp://192.168.1.2/ipp/print > FujiXerox.ppd
$ systemctl start cups
After swapping out the generic PPD for the one created by driverless, the 100mm square is now 100mm. We did it!
In closing, there was a fantastic bit the late John Clarke did in his show The Games, where a bumbling contractor has to justify to the Sydney Olympic Committee that it's fine the 100 metres track he built is only 94 metres long. I'd include a clip, except the ABC decided to copyright strike it. Oh well! Now to give up computers for good this time.