Java (32) - tiskové služby
V minulém dílu (o základech tisku) se vyskytla zmínka o tiskových službách. Ty umožňují postoupit v úrovni abstrakce tisku ještě výše a nemuset zbytečně řešit technické detaily.
21.3.2007 09:00 |
Lukáš Jelínek
| Články autora
| přečteno 20536×
Abstrakce a virtualizace tisku
Za "normálních okolností" musí uživatel přemýšlet o tom, jaké vlastnosti má
ta která tiskárna, má-li jich k dispozici více. Například potřebuje vědět,
která tiskárna vytiskne stránku o velikosti A3, umí tisknout oboustranně
nebo barevně. V praxi to znamená zjistit si předem potřebné informace a
podle toho pak zvolit tiskárnu, na kterou se tisková úloha pošle.
Lepší je ovšem abstraktní pohled - máme nějaké dostupné tiskárny (místní
či vzdálené, nebo i ryze virtuální, tvořené pouhým programem) a tiskovou
úlohu s určitými parametry. Nyní jde o to, aby tisková úloha putovala na
nejvhodnější tiskárnu a nemuselo se o tom příliš přemýšlet.
Tiskové služby v Javě
Standardní knihovny Javy obsahují kompletní aparát pro abstraktní pohled na
tisk. Říká se mu tiskové služby a využívá se skrze aplikační rozhraní
Java Print Service API. Podívejme se na to, co všechno umožňuje:
-
zjišťovat dostupné tiskové služby (tiskárny) a jejich parametry, vyhledávat
služby na základě požadavků určených aplikací
-
automaticky konvertovat data do formátu vyžadovaného určitou službou
-
vytvářet tiskové úlohy s vlastnostmi specifikovanými pomocí atributů
-
určovat datové formáty dokumentů k tisku
Není toho málo, implementace infrastruktury není jednoduchá, ale z hlediska
použití v aplikacích je k dispozici velmi silná nástroj pro řízení tisku.
Návrh JPS API vychází z protokolu IPP
(Internet Printing Protocol).
Princip fungování tiskových služeb
Tisk s využitím tiskových služeb se poměrně značně liší od klasických metod
tisku, třeba i té, kterou jsme používali minule. Základní postup při využití
tiskových služeb je zhruba tento:
- příprava zdrojových dat (výchozího dokumentu) k tisku
- příprava datové třídy pro konkrétní formát tisku
- sestavení sady atributů pro popis požadavků na tisk
- vyhledání tiskárny (resp. tiskové služby), které vyhovuje požadavkům
- vytvoření tiskového dokumentu
- vytvoření tiskové úlohy
- odeslání úlohy tiskové službě
Rozdíl oproti klasickému postupu při tisku je jasně viditelný. Celý proces je
sice poněkud náročnější a zdlouhavější, ale získáváme naopak větší flexibilitu
a méně otrocké práce při tisku.
Příprava třídy pro datový formát
Zatímco při klasickém tisku je víceméně dáno, jak vypadá tištěný dokument
(je to vždy grafický kontext, tedy virtuální plocha, na kterou se kreslí).
Ne tak zde - možnosti tiskových služeb jsou mnohem větší.
Při specifikaci datového formátu se používá standard MIME. Jeho pomocí určujeme,
jaký datový typ bude dokument mít. V základní podobě máme k dispozici tyto formáty:
- prostý text (
text/plain )
- HTML data (
text/html )
- tiskové jazyky (PostScript -
application/postscript , PDF - application/pdf a PCL - application/vnd.hp-PCL )
- grafická data (GIF -
image/gif , JPEG - image/jpeg a PNG - image/png )
- automatická detekce - formát bude rozpoznán tiskárnou (identifikace jako
application/octet-stream )
Každý z popsaných formátů umožňuje používat různé zdroje dat (bajtová pole,
streamy, URL apod.). Ne každý formát podporuje všechny zdroje. Než vytvoříme/získáme
objekt pro práci s formátem, musíme tedy kromě formátu znát i zdroj dat.
Formát je reprezentován třídou DocFlavor z balíku javax.print . Instanci vytvoříme
buď klasicky konstruktorem nebo využijeme některou z podtříd, připravených
pro různé zdroje dat. Zde je několik příkladů získání instance DocFlavor :
DocFlavor df;
df = new DocFlavor("image/gif", "java.io.InputStream");
df = new DocFlavor("text/html; charset=utf-8", "java.io.Reader");
df = new DocFlavor.BYTE_ARRAY("application/octet-stream");
df = DocFlavor.URL.POSTSCRIPT;
První příkaz vytvoří konstruktorem instanci určenou pro obrázek GIF získávaný ze vstupního
streamu. Druhý řádek je podobný, ukazuje ovšem HTML data včetně uvedení znakové sady
(to je důležité, jinak se používá výchozí sada, což nemusí být vždy v pořádku) a data
načítá z textově orientovaného streamu. Dále tu je instance vytvořená pomocí
konstruktoru podtřídy (v tomto případě pro bajtové pole), určená pro automaticky
detekovaný formát. A konečně poslední příklad plně využívá hotové objekty
- v tomto případě se použije instance pro postscriptová data z URL.
Pokud známe předem (při implementaci programu) typ dat a jejich zdroj, používáme
přednostně již vytvořené objekty nebo alespoň specializované třídy. Je to
rychlejší než volat základní konstruktor s textovými parametry.
Atributy tisku
Požadavky na tiskovou službu, a také další vlastnosti tisku, se vyjadřují pomocí atributů. Každý atribut je
instancí třídy implementující rozhraní javax.print.attribute.Attribute . Takových
tříd je velké množství. Většinou nás bude zajímat například MediaSizeName (název
velikosti média), PrinterResolution (rozlišení tiskárny), ColorSupported (podpora
barev v tiskárně) nebo třeba PagesPerMinute (počet stránek za minutu). Většina atributů
odpovídá příslušné reprezentaci v IPP.
S atributy je to ještě trochu složitější. Obecně se dají zařadit do pěti
kategorií (podle účelu), každá z nich je představována jedním rozhraním.
Atribut může patřit do více kategorií současně.
- atribut dokumentu (
DocAttribute )
- atribut tiskové úlohy (
PrintJobAttribute )
- atribut tiskové služby (
PrintServiceAttribute )
- atribut požadavku na tiskovou službu (
PrintRequestAttribute )
- atribut podporovaných hodnot (
SupportedValuesAttribute )
Všechny kategorie mají svůj smysl. Ještě se k nim dostaneme. Další důležitou
věcí je sdružování atributů do sad. Základním rozhraním sady je AttributeSet ,
od něho jsou odvozena další rozhraní, například PrintRequestAttributeSet
(sada požadavků na tiskovou službu).
Nejdříve se podíváme na využití atributů k vyhledání tiskové služby odpovídající
daným požadavkům. Tady je krátký příklad, jak sestavit sadu atributů:
PrintRequestAttributeSet as = new HashPrintRequestAttributeSet();
as.add(MediaSize.ISO_A4);
as.add(Sides.DUPLEX);
as.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
Jak je snad na první pohled zřejmé, takto sestavíme požadavek na tisk na stránku
A4, s možností oboustranného (duplexního) tisku a s rozlišením 300 x 300 DPI.
Lze používat jen atributy implementující rozhraní PrintRequestAttribute - z toho
vyplývá, že některé hodnoty nelze přímo vyžadovat. Tam patří třeba rychlost
tisku (PagesPerMinute ; jedná se stejně jen o informativní hodnotu), ale také
umístění tiskárny (PrinterLocation ; sice by bylo určitě lákavé automaticky zabránit tisku na
tiskárnu umístěnou ve firemní pobočce v Austrálii, nicméně umístění tiskárny
je stejně jen textový atribut - rozhodnout musí uživatel).
Samostatnou zmínku si zaslouží speciální kategorie atributů - atributy
podporovaných hodnot. Slouží k vyjádření hodnot podporovaných jinými atributy.
Tak například atribut JobPrioritySupported říká, jaké hodnoty priorit úloh
(JobPriority ) tisková služba podporuje (ne všechny hodnoty z obecného rozsahu musí být
vždy podporovány, případně nemusejí být podporovány žádné).
Vyhledání tiskové služby
Nyní nastal pravý čas zjistit, které tiskové služby vyhovují určeným požadavkům.
Stačí jednoduše provést dotaz a pak už si jen vybírat z dostupných služeb:
DocFlavor fd = ...
PrintRequestAttributeSet as = ...
PrintService sa[] = PrintServiceLookup.lookupPrintServices(df, as);
Kdo má to štěstí, že mu takový dotaz vrátí větší počet služeb, může si pak vybrat
nejvhodnější službu (viz dále). Mnohdy ale člověk může být rád, že vůbec
nějaká služba prošla jeho sítem.
Celkem snadno se ale stane, že nevyhoví žádná
služba - třeba když zadáme požadavek na duplexní tisk a žádná dostupná tiskárna
ho nepodporuje. To je prostě smůla, takže nezbývá než si to někde v programu
poznamenat a zkoušet dál s menšími požadavky. Lze to i opačně - začít s málem
a postupně přidávat další a další požadavky, dokud nějaké služby zbývají.
Pokud si vystačíme s výchozí tiskárnou, stačí místo zmíněné metody zavolat
lookupDefaultPrintService() . Ovšem pozor - nikde není řečeno, že nějaká tisková
služba vůbec musí být k dispozici.
Ještě zbývá jedna důležitá věc, a to zjišťování atributů určité tiskové služby.
To může sloužit například k ručnímu výběru služby uživatelem (například podle
zmíněného umístění tiskáry, rychlosti tisku, aktuálního stavu tiskárny atd.).
Jednoduše zavoláme instanci tiskové služby (PrintService ) metodu getAttributes()
a pak už pomocí metody get() přistupovat k atributům, nebo použít u služby přímo metodu
getAttribute() se stejným výsledkem. Třída PrintService má ještě pár dalších
zajímavých metod, které se mohou hodit při zkoumání, co služba umí.
Tiskový dokument
I když to není úplně nutné, velice se hodí vytvořit si něco, čemu se dá říkat
"tiskový dokument". Jedná se vlastně o propojení zdroje tiskových dat, formátu
tisku a tiskových atributů. Tiskový dokument je představován rozhraním Doc
(z balíku javax.print ). Ve většině případů nemusíme rozhraní implementovat,
vyhoví totiž předem připravená třída SimpleDoc , obsahující vše potřebné.
Vytvoření instance SimpleDoc je triviální. Zavolá se konstruktor a tomu se
předá zdroj dat, formát a atributy dokumentu. U těchto atributů stojí za to se
chvilku zdržet. Říkají totiž, jaké parametry se mají při tisku nastavit.
Služba by je pochopitelně měla podporovat - nemá smysl se snažit tisknout ze
zásobníku, který tiskárna nemá.
Pokud atributy nepotřebujeme používat, stačí místo sady použít null - není
třeba zbytečně vytvářet prázdnou sadu. Celý postup při vytvoření dokumentu
může vypadat například takto:
HashDocAttributeSet as = new HashDocAttributeSet();
as.add(PrintQuality.DRAFT);
as.add(OrientationRequested.LANDSCAPE);
SimpleDoc sd = new SimpleDoc(data, df, as);
Atributy v příkladu určují použití kvalitativního režimu Draft a orientaci
na šířku. Pozor na to, že některé atributy (například právě orientaci) lze
použít jen u některých formátů - u jiných nemá smysl.
Tisková úloha a její odeslání
Zbývá už jen málo - vytvořit úlohu a poslat ji zvolené službě. Úloha jako
takové se získá velmi snadno. Stačí instanci tiskové služby (PrintService )
zavolat metodu createPrintJob() . Stejně jednoduše se pak úloha spustí - pouhým
zavoláním metody print() . Jediné, na co se nesmí zapomenout, jsou požadované
atributy služby (jako při jejím hledání). Nemusí se použít, pokud nejsou potřeba.
SimpleDoc sd = ...
PrintRequestAttributeSet as = ...
PrintService ps = ...
DocPrintJob job = ps.createPrintJob();
try {
job.print(sd, as);
} catch (PrintException e) {
...
}
Všimněte si, že metoda print() může vyhodit výjimku, kterou musíme ošetřit.
Navíc tato metoda obecně může (ale nemusí) pracovat asynchronně, proto její
opuštění vůbec neznamená, že se něco vytisklo. Pro sledování stavu implementujeme
rozhraní PrintJobListener a přidáme ho do úlohy (metodou addPrintJobListener() ).
Pak např. metoda printJobCompleted() znamená úspěšné dokončení úlohy,
printJobFailed() selhání a tak podobně. Obdobně lze pomocí implementace
rozhraní PrintJobAttributeListener sledovat změnu atributů úlohy (například
změnu stavu).
Vlastní tisková služba
Pro některé účely se hodí vytvořit si vlastní tiskovou službu a pak ji používat.
Může sloužit například k přímému exportu do některého grafického formátu.
Nejjednodušší možností je použít třídu StreamPrintServiceFactory . Ta umožňuje
vyhledat službu odpovídající daným požadavkům. Vypadá to takto:
OutputStream os = ...
StreamPrintServiceFactory fa[] =
StreamPrintServiceFactory.lookupStreamPrintServiceFactories(df,
"application/pdf");
if (fa.length > 0) {
StreamPrintService ps = fa[0].getPrintService(os);
if (ps != null) {
...
}
}
Příklad ukazuje vyhledání služby, která umožňuje (pro daný formát dokumentu)
výstup do PDF. Je-li služba nalezena, připojí se na výstupní stream, který může
představovat například otevřený soubor, síťové spojení, rouru do jiného vlákna
apod.
Existuje ještě další možnost - naimplementovat si přímo celou tiskovou službu.
Ta by se pak, pokud by měla být zahrnuta do vyhledávání podle požadavků,
musela zaregistrovat zavoláním statické metody registerService()
třídě PrintServiceLookup . Jen pro zajímavost, lze implementovat a registrovat
také vlastní vyhledávače služeb (instance PrintServiceLookup ; registrují se
pomocí registerServiceProvider() ), ale to už je poměrně okrajová záležitost.
Tiskové služby a grafický kontext
Zatím zůstávala opomenuta jedna otázka - jak propojit klasickou tiskovou metodu
(z minulého dílu seriálu) s tiskovými službami. Jde to snadno a existují dokonce
dvě rozdílné cesty, jak toho dosáhnout.
První z nich vychází z původního základu, avšak využije mechanismus tiskových
služeb. Tady je příklad z minulého dílu upravený pro tiskové služby:
protected void doPrint(Printable pt) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(pt);
PrintService sa[] = PrinterJob.lookupPrintServices();
if (sa.length > 0) {
try {
pj.setPrintService(sa[0]);
pj.print();
} catch (PrinterException e) {
JOptionPane.showMessageDialog(this,
"Při tisku došlo k chybě: " + e.getMessage(),
"Chyba", JOptionPane.ERROR_MESSAGE);
}
}
}
Pokud bychom chtěli nastavovat atributy tisku, stačilo by vytvořit prázdnou sadu,
pomocí známých dialogů (metody pageDialog() a printDialog() , zde ve verzích
s předáním sady atributů) nastavit požadované hodnoty a pak sadu předat metodě
print() .
Druhou, v podstatě ještě jednodušší metodou je použít postup určený přímo
pro tiskové služby a jako formát zvolit DocFlavor.SERVICE_FORMATTED.PRINTABLE .
Při vytváření instance SimpleDoc se pak jako zdroj dat předá instance
implementovaného rozhraní Printable . Podobně bychom si počínali i při použití
rozhraní Pageable (použil by se formát DocFlavor.SERVICE_FORMATTED.PAGEABLE ).
Opět krátký příklad:
Printable pt = ...
PrintService sa[] =
PrintServiceLookup.lookupPrintServices(
DocFlavor.SERVICE_FORMATTED.PRINTABLE, null);
if (sa.length > 0) {
SimpleDoc sd = new SimpleDoc(pt, DocFlavor.SERVICE_FORMATTED.PRINTABLE, null);
...
}
V příkladu se nepoužívají žádné atributy. Pokud bychom je chtěli použít, prázdné
reference by se nahradily sadou atributů jako v příslušných příkladech z tohoto
článku.
JavaBeans
Přístě konečně přijde řada na to, co kvůli dvěma článkům o tisku muselo počkat
- tedy na úvod do JavaBeans. Věřím, že i tato oblast Javy bude neméně zajímavá,
jako právě popsané záležitosti tisku.
Verze pro tisk
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|