« Tsukurimashou 0.11 release | Home

Fixing cut-off margins and bad paper size in Okular printing

Sat 31 Jul 2021 by mskala Tags used: ,

Ever since a recent "upgrade," the Okular PDF reader on my Slackware Linux system has been printing pages with incorrect margins, adding extra blank space at the bottom of every page and subtracting it at the top in such a way as to cut off part of the print at the top. No configuration changes seemed able to resolve the issue, and it was hard to get any useful debugging information. Searches on the Net found many instances of people having similar problems, but no convincing solutions - and the KDE development team has a history going back at least 13 years of never ever acknowledging or fixing any problems with printing options, always blaming it on the users and erecting unreasonable procedural barriers to bug reporting. Here are some notes on how I was able to fix my problem; it's an ugly fix and may not be useful to everyone with similar issues, but the notes may still be of some use.

Problem: text cut off by Okular shifting it upward on the page

Printers usually cannot print to the very edge of a page. Mine, in particular, has a 0.17" (4.32mm) unprintable margin on all four sides. When printing a PDF, in principle you can send the PDF to the printer with a possible conversion to Postscript but no change to the size, and let the printer print whatever it can, cutting off the unprintable parts. Most documents have more than 0.17" margins on all sides anyway, so there's no loss from doing that. But CUPS can also, semi-automatically, rescale documents to fit the entire PDF page size in just the printer's printable area, so nothing is lost. The "printable area" is configured in the PPD file when you set up the printer queue in CUPS; mine is correctly so configured.

Okular offers three options (under "PDF Options"/"Scale mode" in the print dialog) for how it will handle this issue: "Fit to printable area"; "Fit to full page"; and "None; print original size." Only "Fit to printable area" is practically usable, because it is the default and changes are not retained from one print job to the next, so unless you're willing to dig through the dialog and reset it on every single print job, you're going to end up using "Fit to printable area" on non-exceptional jobs.

My experience was that with "Fit to printable area" and "Fit to full page," the document would print with about 5mm removed at the top (therefore clipping off part of the top of the text if the original document had a top margin of less than 9.3mm, bearing in mind the printer's hard limit of not printing within 4.32mm of the paper edge), and about 13mm extra blank space added at the bottom. With "None; print original size" it would send the original-size document to the printer. That mode would be acceptable for documents with at least 4.32mm margins on all sides, which are most documents, but the requirement to set this manually on every single print job was not acceptable. It also left no useful way to handle documents with less than 4.32mm margins in the PDF file, which really did need some kind of rescaling.

Okular provides a feature (under "Properties"/"Page"/"Margins") for changing the printer's configured 0.17" margins as used by the scaling modes, but it will not allow decreasing the numbers, only increasing them. In particular, it seems impossible to set the bottom margin negative as a workaround to get rid of that extra 13mm blank space at the bottom. Even if it had worked, the requirement to do it on every single print job would be unacceptable. I run a business, printing documents is important to my business, and I need printing to work correctly by default.

Important to note: I am in Canada, where the standard paper size used in offices is 8.5" by 11", often called US Letter. My printer is loaded with US Letter paper, nearly all documents I want to print are PDF files with US Letter paper specified inside the file, and all visible paper configuration options are set to US Letter by default throughout Okular, CUPS, and my other document-handling software. The A4 paper size used elsewhere in the world should not be relevant to my situation at all. Nothing in my system is or should be set to A4. But we'll revisit that point soon...

The KDE development team has a long history of refusing to acknowledge that bad default print settings are a problem at all, much less their problem. Bug number 180051 is probably my favourite of the genre, but there are many other examples. A search on the relevant bug trackers provides a pretty much endless supply of people reporting bad default print settings (especially related to things like paper size and duplexing) and KDE developers refusing to take the issues seriously, pointing fingers at other software, and eventually closing the issues on procedural grounds. Similar bugs get reported to Linux distributions, whose teams direct the reporters to report the bugs upstream to the KDE team, who don't take the bug seriously. Despite being marked "resolved," it's not resolved, you still can't realistically expect to be able to control the default print settings in KDE software, and the general issue of bad printer settings that can't be changed will probably never be resolved.

People get quite nationalistic about paper size in particular - not clear exactly why - and that often adds fuel to the flame war, with the implied solution for a printing problem being "You should move to a different country where the software's behaviour will be correct" instead of any change being needed in the software.

It's also worth noting that nothing in my configuration changed between when it worked and when it didn't, except that I brought Okular and CUPS to the latest versions provided by 64-bit Slackware Current as of mid-2021. I did try rolling back the CUPS upgrade and using a home-compiled version instead, because that's been useful in some previous printing problems, but it didn't help here. All this points at a problem in Okular, introduced by the recent "upgrade." ("Upgrade" in quotes because going from a system that works to one that doesn't is not an upgrade.)

Debugging the CUPS filter pipeline

I tried printing a test page using the buttons on my printer's front panel, without going through the computer at all. The test print came out with normal margins, balanced between top and bottom. From that I concluded the problem wasn't a mechanical misalignment in the printer forcing the printed image to appear shifted upward relative to the paper. I've seen such misalignments before, so I wanted to rule it out even though I didn't think it was very likely this time.

One important test I saw mentioned on several pages around the Net: did the problem happen from the command line? I tried sending PDF documents to the printer with the command-line "lpr" program. What I got seemed to be the same as the "None; print original size" option in Okular: text printed in the correct position on the page, but no scaling, so PDF files with very narrow margins would be cut off. This result didn't help much because it didn't mean I could print anything this way that I couldn't already print with Okular, but it also didn't definitively tell me that the problem was or wasn't Okular's fault. It may be that there is an option I could've passed to "lpr" to tell it to rescale, the same way as the "PDF Options"/"Scale mode" setting in Okular, and then I could have recognized whether there was something special about Okular causing it to fail when other CUPS-using software didn't; but I ended up finding that out from other tests.

Also worth checking: whether other software had the same problem. I don't have much other software that sends documents to the printer, and I'm not sure I have any that sends PDF files in particular except Okular, xpdf, and lpr. The xpdf program didn't offer a selection of scaling modes and its behaviour seemed to be the same as lpr's, or Okular's with "None; print original size"; again inconclusive.

I set the PreserveJobFile option in my cupsd.conf file and sent a few jobs to the printer. This option tells CUPS not to delete the temporary files it normally creates in /usr/spool/cups. For each job it creates files named like c00501 (a binary file containing text strings naming variables that have been set for the print job) and like d00501-001 (the document sent to the printer; ASCII Postscript in my case). Here's what I saw in the ASCII Postscript file.

%!PS-Adobe-3.0
%Produced by poppler pdftops version: 21.07.0 (http://poppler.freedesktop.org)
%%Title: testfile.pdf
%%LanguageLevel: 2
%%DocumentSuppliedResources: (atend)
%%DocumentMedia: A4 595 842 0 () ()
%%BoundingBox: 0 0 595 842
%%Pages: 2
%%EndComments
%%BeginDefaults
%%PageMedia: A4
%%EndDefaults

The text strings in the binary control file also mentioned "A4." It was clear that although I had started with a US Letter PDF file, printed it in Okular with the page size set to US Letter, to a printer loaded with US Letter paper and its default page size set to US Letter in the CUPS configuration, nonetheless something along the way was converting it to A4.

Note that A4 paper is a little narrower and a little taller than US Letter paper. If you started with a US Letter page and tried to fit it onto an A4 page for printing, you might do it by shrinking it a little to fit the width, then centering the result vertically on the A4 page, adding some white space at top and bottom. If you then printed the A4 rescaled version on a US Letter page with a printer properly configured, anchoring at the lower left corner, you'd see the added whitespace at the bottom, and you'd run off the top. That seems like a description of what was happening to my pages. It appears that when asked to fit the file to the page - which is the unchangeable default - my system was ignoring the fact that the "page" was everywhere configured to be US Letter, and fitting to an A4 page instead before sending that to the US Letter print queue. That seemed to explain all the observed symptoms. The problem wasn't really "shifting" the print or clipping the margins, though that was the main visible manifestation; the real problem was the uncalled-for conversion to A4. It remained to determine which part of the system was doing that and how it could be changed.

I tried Okular's "print preview" - which does not allow setting any options, but we might guess it may use Okular's defaults, in particular for scaling - and I saw that it was adding a white band at the top and bottom of the page while seemingly filling the entire width. Print preview did not give any direct indication of what page size it was displaying, but the pattern of fitting to a taller aspect ratio than the original US Letter PDF would be consistent with Okular thinking that it is printing to A4, regardless of configuration.

I got some use out of the "cupsfilter" command as described on this Debian Wiki page. This command purported to run the same filters that CUPS would use for submitted print jobs, while giving debug information on what it was doing:

/usr/sbin/cupsfilter -d zinc -P ../zinc.ppd -c /etc/cups/cups-files.conf \
   -m application/vnd.cups-postscript testfile.pdf > outfile

Here's a clip from the standard error debug output of that:

DEBUG: Started filter gs (PID 27158)
DEBUG: Started filter pstops (PID 27159)
DEBUG: Page = 612x792; 12,12 to 600,780
DEBUG: slow_collate=0, slow_duplex=0, slow_order=0
DEBUG: Before copy_comments - %!PS-Adobe-3.0
DEBUG: %!PS-Adobe-3.0
DEBUG: %%Invocation: gs -q -dNOPAUSE -dBATCH -dSAFER -dNOMEDIAATTRS -sstdout=? -sDEVICE=ps2write -dShowAcroForm -sOUTPUTFILE=? -sProcessColorModel=DeviceGray -sColorConversionStrategy=Gray -dLanguageLevel=3 -r1200 -dCompressFonts=false -dNoT3CCITT -dNOINTERPOLATE
DEBUG: %%+ ? ? -f ?
DEBUG: %%BoundingBox: 0 0 612 792
DEBUG: %%HiResBoundingBox: 0 0 612.00 792.00
DEBUG: %%Creator: GPL Ghostscript 9533 (ps2write)
DEBUG: %%LanguageLevel: 2
DEBUG: %%CreationDate: D:20210731151645-04'00'
DEBUG: %%Pages: 2
DEBUG: %%EndComments

Note that the size 612 by 792 Postscript units, at 72 units per inch, translates to 8.5" by 11", that is, US Letter and not A4 size. This suggests CUPS isn't rescaling to A4 on its own initiative for all jobs; it's only when I print through Okular. Not quite a smoking gun, though, because it's not clear to me whether this command is asking CUPS to "rescale to page size" and if it's not, I don't know how to make cupsfilter ask for that. So it could be that here I'm just seeing the usual "None; print original size" that I can get from the lpr command.

I tried setting "LogDir /var/log/cups" and "DebugLogging file" in /etc/cups/cupsd-browsed.conf. (It seems very odd that that's where these settings would be - they have nothing to do with the "browser" feature of CUPS - but that is where they are.) This generated a lot of debug information in /var/log/cups/error_log, including a few mentions of page size that implied CUPS was seeing the documents from Okular as being A4-sized, but no information about where that was configured. All this added up to Okular somehow forcing the documents to A4 size before passing them to CUPS, or possibly requesting CUPS to rescale them to A4 somewhere early in the pipeline.

I checked out a copy of the latest Okular source code from its development site and used grep to search it for any mention of "A4" and "letter". I wasn't able to quickly figure out exactly how it determined paper size (I'd been hoping to find a config file it was reading, or maybe a hardcoded assumption) but I did find, somewhat to my surprise, that Okular usually does its printing by running command-line programs with hardcoded names. In particular, the function FilePrinter::doPrintFiles in the source file core/fileprinter.cpp says that for "print to file," if you have a Postscript or PDF file and request printing to a file of the same type it will just pass the file through; if you have a Postscript file and request printing to a PDF file it will run "ps2pdf"; if you have a PDF file and request printing to a Postscript file it will run "pdf2ps"; in other cases of file format conversion with print to file, it will fail; and if you ask to print to a real printer, it will run the first command found from the list "lpr-cups", "lpr.cups", "lpr", and "lp". I had been expecting that it would call out to some kind of Qt general printing library, or invoke a dbus thing, but no, Okular just invokes the command-line commands. There was some logic to assemble a set of options for the command-line programs, including an option for paper size, but it wasn't obvious to me where that information came from. That at least wasn't hardcoded.

The great thing about having Okular invoke a command-line program is that command-line programs can be overridden. I moved my real /usr/bin/lpr file (which was the only one from the list installed on my system) somewhere else and replaced it with this small script before doing a test print:

#!/bin/bash
echo $* > /tmp/lpr-log

Here is what it put in /tmp/lpr-log (wrapped):

-P zinc -#1 -J testfile.pdf -o media=A4
   -o portrait -o sides=two-sided-long-edge -o outputorder=normal
   -o Collate=True -o page-left=12.5 -o page-top=12.5 -o page-right=12.5
   -o page-bottom=12.5 -o fit-to-page -o number-up=1
   -o number-up-layout=lrtb -o job-billing -o job-priority=50
   -o job-sheets=none,none -r /tmp/okular_uNdLYq.ps

That "-o media=A4" is the smoking gun. Okular is requesting A4 paper size on every job, despite showing "Letter" as the paper size in the print dialog and despite all configuration.

I was never able to determine why Okular is doing that. Every place I can find where paper size would be configurable was and is set to US Letter. My best guess is that, as I've seen Okular do before, it's ignoring the configuration and then using some kind of default because it has not read the configuration. I also think there's no realistic hope of getting an answer from KDE as to why this is happening, let alone an acknowledgment that having this happen is in any way less than ideal.

However: if the problem is being caused by a bad command line option when Okular invokes lpr, that's something I can work around.

A messy workaround for getting correct paper size with Okular

I never want to print to A4 paper through my current CUPS installation. I don't have any A4 paper to print on. If something on my system tries to run /usr/bin/lpr with "-o media=A4" then that is always incorrect; in such a case the system should always use "-o media=Letter" instead. So... let's make it do that!

I moved my real lpr program to /usr/bin/saved-lpr and put this small Perl script in /usr/bin/lpr:

#!/usr/bin/perl
 
for ($i=0;$i<=$#ARGV;$i++) {
  if ($ARGV[$i]=~/^media=a4/i) {
    $ARGV[$i]='media=Letter';
  }
}
 
exec '/usr/bin/saved-lpr',@ARGV[0..$#ARGV];

I used Perl because I know it better than I know bash and so I'm more confident that this will work without surprises, than I would be an equivalent Bash script; but it surely could be done in Bash too. What the code says is that when anything (in particular, Okular) runs /usr/bin/lpr, it will scan through the arguments list for any that start with "media=a4" (case insensitive, meant to include variations like "a4-foo-special-media" or whatever if they should occur), and if it finds any such argument, it replaces it with "media=Letter". Then it runs the real lpr program with the possibly-edited arguments.

With this override, printing PDF files using Okular's default setting of "Fit to printable area" results in correct rescaling to the US Letter paper that's in my printer, without extra space at the bottom nor clipping at the top. It's a messy way of solving the problem, but it works, and having it work is more important to me than having it be pretty.

If for some reason I ever do get some A4 paper and want to print on it with this installation and no other changes, I can run /usr/bin/saved-lpr with "-o media=A4".

I don't plan to attempt to report the bug through the official channels to the KDE development team because, based on their track record over many years with printer options bugs in particular, I don't trust them to take the problem seriously, and I'm not willing to waste my time. But I'm posting about it here in the hope that it can be found by people who are making the same kinds of search engine queries I was making when looking for a solution.

0 comments



(optional field)
(optional field)
Answer "bonobo" here to fight spam. ここに「bonobo」を答えてください。SPAMを退治しましょう!
I reserve the right to delete or edit comments in any way and for any reason. New comments are held for a period of time before being shown to other users.