Moje odkazy
Obsah článku:
vydáno: 29. 6. 2020 01:15, aktualizováno: 14. 4. 2023 20:06
Problém s tiskárnami je, že… Nechci dnes mluvit o hardwarových závadách (jako že vám třeba zaschne náplň v inkoustové tiskárně), ale o těch softwarových. V dobách, kdy jsme běžně k počítačům připojovali jehličkové tiskárny pomocí paralelního portu, byla situace v lecčems jednodušší – s tiskárnou jsme komunikovali více napřímo a ta poslušně plnila naše příkazy (takže jsme si třeba potiskli místo papíru válec, když jsme zadali špatné rozměry). S tím, jak roste komplexita softwaru, přibývají v systému další mezičlánky – a ty občas kompenzují chyby uživatele a jindy mu přidělávají starosti. Potištěných válců ubylo, ale zmuchlaných papírů v koši je pořád dost.
To si třeba nastavíte v LaTeXu třícentimetrové okraje a vytisknete zkušební stránku. Je to lepší než výchozí nastavení (které oceníte, když píšete diplomku, protože vám rychleji přibývají stránky, ale jinak je dost nepraktické), ale pořád je to nějaké divné, tak vezmete do ruky pravítko a naměříte 3,5 cm. To není chyba omluvitelná nějakou mechanickou nepřesností tiskárny – tady je něco špatně.
Je chyba v TeXu? Nebo jsem špatně pochopil parametry příkazu \usepackage{geometry}
? Rozbila mi to PDF knihovna nebo PDF prohlížeč, přes který jsem to posílal do tiskárny? Vstoupil do toho nějaký CUPS filtr? Nebo je chyba v tiskárně? Ta mrcha má dneska v sobě malý počítač s vlastním OS, byť se navenek tváří celkem nevinně se svým dvouřádkovým LCD displejem, pár tlačítky a retro webovým rozhraním.
Teď by se nabízela metoda půlení intervalu, ale nechce se mi psát ručně PostScript a zkoušet ho tam procpat od prostředka, abych zjistil, jestli je chyba spíš na té polovině cesty směrem k tiskárně nebo na té druhé směrem k uživateli. Tak to zkusím rovnou od druhého konce: dávám PDF soubory na USB flashku a nesu je k tiskárně – ta má USB port a nabízí tzv. přímý tisk. Ovládání přes ten malý displej a pár tlačítek je docela použitelné. Tiskárna tiskne… a další makulatura je na světě. Výsledek je o nějaký ten milimetr lepší, ale stále je to celé špatně. Až tak „přímý“ tisk to tedy nebude. Beznaděj. Moje tiskárna je zmetek, který neposlouchá a dělá si, co chce.
Pak si ale matně vzpomínám, že jsem na téhle tiskárně kdysi vytiskl podací lístek na poštu, který má mít přesné rozměry 133×90 mm, takže nějaká šance tu přeci jen je. Vracím se tedy k počítači. Program pdfTeX mám ve verzi 3.14159265 a jak známo, jeho verze konvergují k číslu Pi a tím k dokonalosti, takže tahle verze by měla být dost dobrá. Tady problém nebude. Přes uživatelské rozhraní CUPS – http://localhost:631/
– nic relevantního nastavit nejde (to jsem zkoušel hned na začátku). Tak jdu hledat konfigurační soubory pro moji tiskárnu a nacházím /etc/cups/ppd/*.ppd
. Zaujaly mne řádky:
*ImageableArea A4/A4: "18 36 577 806" *PaperDimension A4/A4: "595 842"
To první bude asi tisknutelná oblast a to druhé velikost stránky. Sice těm číslům nerozumím, ale vzhledem k tomu, že ImageableArea
nezačíná na nule a nejde až k 595×842, značí to nějaké okraje – tady se rýsuje šance na rychlé řešení…
Zatímco 210×297 mm si normální člověk ještě občas pamatuje. Čísla 595×842 působí dost tajemně. V PostScriptu a tím pádem i PPD (PostScript Printer Description) se jako jednotka nepoužívá mm ale typografický bod – a to ve variantě z roku 1984 definované jako 1/72 palce, což je 0,3527 mm. A značí se jako pt, alespoň tedy v PostScriptu (zatímco v TeXu se značí bp, protože pt tam znamená 0,35145980).
…zpět k přízemním starostem s tiskárnou. PPD soubor, který jsem si zkopíroval z /etc/cups/ppd/
tedy upravuji na:
*ImageableArea A4/A4: "0 0 595 842"
Tiskárna samozřejmě nějaká hardwarová omezení má a netiskne až do krajů, ale s tím se bude muset vypořádat sama. Mně jde teď o to, aby moje stránky nenarušoval software před ní – plán je prostý: software si bude myslet, že se dá tisknout všude, a bude tak stránky beze změn posílat rovnou do tiskárny. V CUPS si tedy konfiguruji novou tiskárnu (budu tam mít dvě směřující na stejné URL té jedné fyzické) a místo, abych vybral v nabídce výrobce a model, přikládám svůj upravený PPD soubor.
Plán vyšel! Když teď zvolím správnou tiskárnu a v dialogovém okně Vlastnosti tiskárny nastavím nulové okraje (což dřív samo o sobě nestačilo), tak se dokument vytiskne ve správném měřítku.
Pokud do tiskárny pošleme stránku, která má nějaký obsah i v netisknutelné oblasti, nedojde k žádné tragédii – tato část se pouze nevytiskne (viz první obrázek v tomto článku – čára v PDF vedla až k okraji stránky). Tzn. dokument se ořízne, ale nezmenší.
Svým způsobem se dá pochopit, že procesy kolem tisku a výchozí nastavení budou optimalizované pro běžné uživatele, kteří dají spíš přednost tomu, aby se jim vytisklo všechno (i za cenu změny měřítka). Nicméně zmenšovat stránku i v případě, že se mimo tisknutelnou oblast nenachází žádný obsah, je přinejmenším nadbytečné. Byť samozřejmě chápu, že zjišťovat, zda nějaký obsah mimo tisknutelnou oblast existuje, je implementačně náročnější, než jen porovnat deklarovanou velikost papíru dokumentu s deklarovanou tisknutelnou oblastí tiskárny.
Tisk v přesném měřítku se hodí v mnoha situacích – pro vyplňování různých formulářů (třeba ty podací lístky na poštu), tisk šablon (air brush atd.) nebo třeba výrobu plošných spojů (metoda přenosu toneru nebo tisk na průhledné fólie). Ve výkresech by sice všechno mělo být okótované a neměly by se z nich rozměry odměřovat pravítkem, ale ani to není důvod tisknout vše o trochu menší. A i když tiskneme „jen“ text, je žádoucí zachovat měřítko – aby znaky a okraje měly ten rozměr, který jsme jim nastavili a ne nějaký náhodný.
Výše uvedené řešení byla tak trochu střelba od boku, která náhodou vyšla. Specifikace formátu PPD má 240 stránek a otevřel jsem ji až po vyřešení problému. Zde se dozvíme různé další věci, jako že existuje parametr HWMargins
.
Abychom lépe viděli, co se děje uvnitř tiskového subsystému, je dobré si zvýšit úroveň logování. To lze udělat příkazem cupsctl --debug-logging
, ale ten nám ze souboru /etc/cups/cupsd.conf
zároveň vymaže všechny komentáře, takže si úroveň raději nastavíme ručně:
LogLevel debug
A restartujeme CUPS, např.:
systemctl restart cups
Logovací soubor /var/log/cups/error_log
se nám začne plnit spoustou zajímavých informací. Navzdory svému názvu neobsahuje jen chybové hlášky.
Z logu zjistíme, že náš dokument prochází přes foomatic-rip
(raster image processor) a další filtry, konkrétně gstoraster
a pdftopdf
nacházející se v adresáři /usr/lib/cups/filter/
. A hlavně tu máme zaznamenané proměnné prodtředí a CLI parametry, kde vidíme mj. parametr fit-to-page
. Pozorný čtenář už asi chápe, proč slova vyšla a vyřešení výše byla psaná kurzívou… Příběh ještě nekončí a věc je, jako obvykle, složitější, než se na první pohled zdá.
Poznámka: Kromě čtení logů můžeme pomocí Wiresharku odposlouchávat komunikaci mezi CUPS a tiskárnou (pokud jde o síťovou tiskárnu implementující protokol IPP). Wireshark tento protokol umí dekódovat (jde o nadstavbu nad HTTP) a díky tomu z něj můžeme vytáhnout .ps
(PostScript) soubory, které odešly do tiskárny, a sledovat i další komunikaci s ní.
Po nahlédnutí do zdrojových kódů CUPS zjistíme, že řetězec fit-to-page
se nachází jen v těchto souborech:
test/5.6-lpr.sh test/5.5-lp.sh filter/pstops.c doc/help/options.html cups/encode.c
A ani jeden z nich nenasvědčuje tomu, že by tuto volbu CUPS doplňoval automaticky. Podezření se tedy přesouvá na aplikaci, která tisk zadala, což je v našem případě Okular (PDF prohlížeč z KDE). Pro jistotu si ho spustíme přes strace
, který nám zaloguje systémová volání:
strace -ttfo okular.strace.log -s 4096 okular test-2.pdf
Zadáme tisk a Okular ukončíme. Mimochodem, v CUPS můžeme tiskárnu pozastavit, abychom negenerovali další potištěné papíry (výsledek už známe). V logu okular.strace.log
nás bude zajímat systémové volání exec*()
, protože předpokládáme, že Okular spouští lpr
(CLI rozhraní CUPS). Tohle volání zde skutečně najdeme včetně všech parametrů:
15558 20:49:02.126094 execve("/usr/bin/lpr", ["lpr", "-P", "tiskarna", "-#1", "-J", "test-2.pdf", "-o", "media=A4", "-o", "portrait", "-o", "sides=one-sided", "-o", "outputorder=normal", "-o", "Collate=True", "-o", "page-left=18", "-o", "page-top=36", "-o", "page-right=18", "-o", "page-bottom=36", "-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_t21413.ps"], 0x7ffeffad7e10 /* 63 vars */ <unfinished ...>
Jdeme se tedy podívat na zdrojové kódy Okularu. A hledáme:
$ grep -lr fit-to-page core/fileprinter.cpp
To je ale nejnovější verze – tu téměř jistě nainstalovanou nemáme, takže nás zajímá spíš historie. V případě gitu ji můžeme prohledat takto:
$ git log --all --oneline -G "fit-to-page" 748884b4c PDF: Implement scaling options for non-rasterized printing 466eb7961 Use QStringLiteral 5a1afc51e Pass down to lpr the printer margins
Mimochodem, v Mercurialu slouží k podobnému prohledávání historie příkaz hg grep
.
Nebo včetně časů a celých zpráv:
$ git log --all -G "fit-to-page" commit 748884b4c74d6636accc29be96065114e42990ba Author: Michael Weghorn <…> Date: Sun Apr 14 21:08:59 2019 -0600 PDF: Implement scaling options for non-rasterized printing Summary: This adds another 'FilePrinter::printFile' method that accepts an additional parameter to specify whether or not to do scaling and passes the 'fit-to-page' to CUPS dependent on what is specified. If FilePrinter is used, The PDF generator now passes this option depending on the scaling mode that was selected in the custom print options widget, which is therefore now enabled for non-rasterized printing as well. Test Plan: 1) open a PDF document in Okular and open the print dialog 2) go to the "PDF Options" tab 3) verify that "Force rasterisation" is disabled, but the "Scale mode" combobox is active. 4) test all the three options available in the "Scale mode" combobox do what they say 5) Make sure the three options still work as expected for the "Force rasterisation" case. Reviewers: #okular, ngraham, sander Reviewed By: ngraham Subscribers: aacid, fvogt, okular-devel Tags: #okular Differential Revision: https://phabricator.kde.org/D18179 commit 466eb79615ba313ff6ef418177a15a6961fbfb36 Author: Montel Laurent <…> Date: Thu Oct 29 13:37:11 2015 +0100 Use QStringLiteral commit 5a1afc51e3bbe78cf9af2870ae41bf2eb79e7a64 Author: Albert Astals Cid <…> Date: Tue Oct 29 20:44:48 2013 +0100 Pass down to lpr the printer margins This makes automagically work the printing on printers with hard-margins since the QPrinter dialog margins are initialized to the printer hard-margins. If you still want the old and mostly unuseful behaviour of not having any margin (and thus your printer not printing things on the borders) you can always set the margins to 0 in the dialog BUGS: 319476 FIXED-IN: 4.12.0
Změna z roku 2015 zjevně není zajímavá. Relevantní jsou změny z let 2013 a 2019. Verze Okularu, kterou používám, v sobě nezahrnuje změnu z roku 2019. V Kubuntu 20.04 LTS totiž dialog vypadá jinak:
než v Kubuntu 18.04 LTS, kde jsem na problém narazil – tam totiž volba „Režim škálování“ vůbec není.
Dle zdrojových kódů se po té změně z roku 2019 volba fit-to-page
nepřidává, když vybereme „None;print original size“, což jsem i ověřil pomocí strace
v Kubuntu 20.04 LTS. Po změně z roku 2013 se ale volba fit-to-page
nastavovala vždy. Dle toho, co píše Albert Astals Cid:
If you still want the old and mostly unuseful behaviour of not having any margin (and thus your printer not printing things on the borders) you can always set the margins to 0 in the dialog
to asi tehdy fungovalo a po nastavení nulových okrajů v dialogu se vytiskla nezmenšená stránka. To by znamenalo, že mezitím došlo k nekompatibilní změně rozhraní CUPS a jeho filtrů (tzn. možná se při nastavení nulových okrajů změna měřítka neaplikovala, zatímco teď ano).
Další možné vysvětlení by bylo, že se v PPD souboru (ovšem to by muselo být jak v tom mém, tak v tom, se kterým to testoval Albert Astals Cid) změnila hodnota ImageableArea
případně HWMargins
(pokud na to má vliv). Ale dle historie foomatic-db je PPD soubor pro moji tiskárnu stále stejný už od roku 2010. Mimochodem, pokud byste třeba v Debianu nebo Ubuntu hledali PPD soubory pro nenainstalované tiskárny, tak je nenajdete. Místo nich tam máte /usr/lib/cups/driver/openprinting-ppds
, což je skript v Pythonu, který v sobě má textovou proměnnou s velmi dlouhým řetězcem (celý ten skript má přes 5 MB) ve formátu Base64, uvnitř kterého jsou zkomprimované všechny PPD soubory. Tohle raději nebudu komentovat. PPD soubory si můžeme vypsat pomocí openprinting list
a jeden konkrétní získat pomocí openprinting-ppds cat URI
(kde URI začíná openprinting-ppds:
a jde o první sloupec z výpisu). Získání jednoho PPD souboru na mém ne úplně pomalém počítači s SSD diskem trvá dva a půl vteřiny. Tím se vysvětluje, proč přidávání nové tiskány přes CUPS není zrovna dvakrát rychlé.
Jaké z toho plyne ponaučení?
Toto patří mezi základní dobré praktiky. A ty jsou nezávislé na programovacím jazyku, paradigmatu či metodice. Dokud si je neosvojíme, nemá smysl doufat, že změna technologie nebo čehokoli jiného za nás vyřeší naše problémy.
Za tento článek zatím nikdo autora nekamenoval