17 юли 2008

Печат с qt4 под линукс

Едно от хубавите неща на свободния софтуер е, че с него може да се постигне всичко за крайно време. Вярно, че някой път това отнема по-малко от час, а друг път се точи с дни, но при наличие на желание няма невъзможни неща. Най-забавната случка, която съм имал, бе свързана с подкарването на една ISDN връзка под linux. След няколко часа борене, решихме да погледнем изходния код на драйвера на картата, за да разберем защо не стават нещата (имаше някакво съобщение за грешка) и веднага разбрахме, че не сме включили правилния кабел, където трябва. Ако правехме това нещо под windows едва ли щяхме да разберем за тази дребна грешка.

За съжаление борбата ми с печатането от qt4 програма под linux не беше толкова кратка (май съм отделил към 40 часа) и честно казано е малко спорно до колко краят е успешен. В тази връзка се сблъсках и с един от основните проблеми сред решенията с отворен код, който е свързан с това, че за да се свърши конкретна работа се ползват каскадно доста наброй приложения. Те от своя страна се развиват и начините на комуникации се изменят. При тези промени се чупи връзката между тях и в цялата тази ситуация не е ясно кой е виновен - извикващият или извикваният? Поради тази причина си мисля да споделя натрупаният опит, който макар и след 6 месеца да не е вече актуален, може да е от полза на някой.

Всичко започна със следния казус – едно и също приложение веднъж реализирано на qt3 и веднъж на qt4 печата в qt3 варианта си, а в qt4 варианта си не иска (всъщност на един от принтери печатът даваше грешка, а на друг просто част от текста беше отрязан). Разбира се, в такава ситуация веднага идва на ум, че проблемът е в qt4 библиотеката, която в конкретния случай бе 4.2.1. Всъщност проблемите се оказаха няколко, като част от тях са решени в qt 4.4.0, но имаше и такива в cups (поне във версия 1.2.7).

Може би сега е моментът да кажа как е организиран печата под linux. Като че ли в повечето случаи хората използват cups, който прави какви ли не работи. Qt4 библиотеката не прави изключение и, ако е компилирана (стандартно е) с такава опция, също го използва. Тук идва и първия нюанс. До преди 4.4 версията qt4 печата използва lpr командата като през тръба предава към нея това, което генерира като печат. Всичко хубаво, но е много вероятно тази команда да не ви е инсталирана. Особено ако правите минимални инсталации и bsd style командите на cups са пропуснати. От версия 4.4 нагоре работата вече е друга, тъй като печата става директно през cups библиотеката, като печата се съхранява във временен файл.

Интересно е в какъв формат се генерира това, което ще се отпечати? Отговорът е в native формат, което за windows и mac може би е ясно какво означава, но за linux e postscript при cups < 1.0.2 и pdf за по-високите версии. Всъщност точно тази иновация чупи печата по няколко линии. От една страна повечето програми ползват postcript към cups и съответно има разни неизчистени проблеми с използването на pdf (например landscape печат при pdf формат). От друга страна в qt3 се ползва postscript и тези нововъдения в qt4 променят доста логиката и не са тествани достатъчно. Например в qt 4.2.1 (оправено е в 4.4.0) при използване на pdf формат не се зареждат коректно данните за принтерите, което прецаква печата в ранна фаза. Принципно човек може явно да укаже дали да ползва pdf или postscript формат при печат, но с това се натриса на следващия проблем, който се наблюдава при печат на landscape неща. Ако се печата в pdf формат към cups трябва да се предаде параметър landscape, но ако се печата в postscript той трябва да се пропусне. Пичовете от Trolltech са съобразили това нещо, но за съжаление го правят на база версия на cups и пропускат факта, че програмата само може да си е избрала формата за печат. Единствения начин да се спасите от този проблем (освен да чакате коригирана версия или сами да пачвате библиотеката) е вие да укажете каква външна програма да се ползва. В този случай qt4 не слага допълнителни опции към командата освен името на принтера. Лошото е, че ако се налага и вие не може да слагате и за целта трябва да минавате през външни скриптове. Което прави работата съвсем куца. Явно, докато KDE4 не влезе в масова употреба, проблемите с печата няма да се изчистят. Принципно, ако не ви се налага на печатите landscape, qt 4.4 ще свърши работа. Отделен е въпросът дали върви във всяка дистрибуция (в debian etch го няма и правенето на пакети за него беше едно голямо изживяване най-малкото, защото засмука 4G от диска и трябваше ударно да трия неща, за да не се окаже, че съм батисал няколко часа), макар че тези, които ще предлагат kde 4.1 ще го мъкнат. Ако сте в останалите случаи, то временно ще ви се налага да правите хватки като описаните по-горе, което в код се изразяват на нещо от сорта:

void print()
{
QPrinter* printer = new QPrinter();
QPrintDialog printDialog(printer, this);
if (printDialog.exec() == QDialog::Accepted)
{
#if defined (Q_OS_UNIX) && ! defined (Q_WS_MAC)
if (printer->outputFileName().isEmpty())
{
printer->setOutputFormat(QPrinter::PostScriptFormat);
printer->setPrintProgram("/usr/bin/lpr");
}
#endif

}
}

Няма коментари: