Občas se dostaneme do situace, že potřebujeme vyplnit formulář, který se má dále zpracovat. Pokud je vyplněný formulář v elektronické podobě, není problém z něj ta data dostat, jak ukazuje část kódu níže. Pokud se ale mají data přečíst z papírové podoby, nastává zde drobnější problém. Je možné formulář naskenovat a pomocí OCR data získat. To ovšem nemusí fungovat zcela spolehlivě, například, když vznikne další verze formuláře, kde se změní design nebo názvy polí.

Další možností je formulář opatřit před tiskem čárovým kódem. Čárových kódů je velké množství a mají různé vlastnosti. Pro uložení většího množství dat jsou vhodné 2D čárové kódy (QR Code, DataMatrix, PDF 417 a další). V níže uvedeném příkladu je použit čárový kód PDF 417. Pro ostatní čárové kódy by níže uvedený kód byl identický až na malé odlišnosti.

Vytvoření PDF formuláře

PDF formulář je možné vytvořit několika způsoby. Adobe nabízí k tvorbě formulářů Adobe LiveCycle Designer ES popřípadě Adobe Acrobat. Jsou to ale komerční produkty a pro většinu uživatelů je zbytečné si je pořizovat. V letech 1998 – 1999 přišel Bruno Lowagie s prvními verzemi knihovny iText pro Javu pro práci s PDF dokumenty a formuláři. Postupem času dokonce i firma Adobe použila tuto knihovnu ve svých řešeních (například Adobe LiveCycle).

Následující kód vytvoří jednoduchý PDF formulář se dvěma poli, která se budou jmenovat „firstName“ a „lastName“:


Document doc = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(filePath));
doc.open();
PdfContentByte canvas = writer.getDirectContent();
Rectangle rect;
TextField text;
PdfFormField field;
// počátek je v levém dolním rohu
rect = new Rectangle(120, 800, 200, 820);
text = new TextField(writer, rect, "firstName");
field = text.getTextField();
// vloží titulek k poli a bude zarovnán vlevo
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase("First name:"), 40, 804, 0);
writer.addAnnotation(field);
rect = new Rectangle(120, 770, 200, 790);
text = new TextField(writer, rect, "lastName");
field = text.getTextField();
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase("Last name:"), 40, 774, 0);
writer.addAnnotation(field);
doc.close();

Formuláře mohou obsahovat samozřejmě i jiné prvky, jako například check box, radio button, seznam (select box), combo box, podpisové pole, …

Naplnění formuláře daty a vytvoření 2D čárového kódu (PDF 417)

Pokud nemáme Adobe Acrobata nebo formulář nemá nastavena tzv. Reader Extensions, které povolují určité úkony, jež s běžným formulářem v Adobe Readerovi nejdou (jako například uložit vyplněný formulář, zavolat JavaScript uvnitř formuláře, …), můžeme opět použít knihovnu iText.

Následující kód naplní daty PDF formulář a kopii uloží na disku:

PdfReader reader = new PdfReader(path);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(filePath));
AcroFields form = stamper.getAcroFields(); // vytáhne z formuláře všechna pole
for (FormData item : data) {
// do formulářového pole, které získá podle jména uloží hodnotu
form.setField(item.getFieldName(), item.getFieldValue());
}
StringBuffer content = new StringBuffer();
for (FormData item : data) {
content.append(item.toString() + ";");
}
BarcodePDF417 pdf417 = new BarcodePDF417();
pdf417.setText(content.toString());
Image img = pdf417.getImage();
// nastaví pozici umístění čárového kódu
img.setAbsolutePosition(40, 720);
// vezme první stránku z upravovaného PDF dokumentu a vloží čárový kód
stamper.getOverContent(1).addImage(img);
/*
* Formulář je zatím stále editovatelný a může jej kdokoliv vyplňovat a měnit data.
* Aby se zabránilo tomu, že by někdo změnil obsah formulářových polí, a tím by
* neodpovídal obsah polí tomu, co je uloženo v čárovém kódu, formulář se "zploští",
* tedy se z něj stane obyčejný PDF dokument ve kterém nejsou editovatelná pole.
*/
stamper.setFormFlattening(true);
stamper.close();
reader.close();

Přečtení dat z čárového kódu

Knihovna iText bohužel neposkytuje možnost čtení a dekódování čárových kódů. K dekódování můžeme použít knihovnu ZXing od Google.

Následující kód přečte ze souboru s čárový kódem, který byl pořízen naskenováním a uložen jako obrázek (v tomto případě ve formátu *.png – jsou podporovány i jiné formáty), veškerá data. Těmito daty můžeme naplnit opět formulář a uložit nebo data jen uložit do databáze.


BufferedImage img = ImageIO.read(new File(path));
PDF417Reader reader = new PDF417Reader();
LuminanceSource source = new BufferedImageLuminanceSource(img);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result = reader.decode(bitmap); // Zde je uložen celý obsah čárového kódu

Použité závislosti pro maven

<dependency>
<groupid>com.itextpdf</groupid>
<artifactid>itextpdf</artifactid>
<version>5.1.3</version>
<type>jar</type>
</dependency>
<dependency>
<groupid>com.google.zxing</groupid>
<artifactid>core</artifactid>
<version>2.0</version>
</dependency>
<dependency>
<groupid>net.ju-n.bonita.connectors</groupid>
<artifactid>bonita-qrcode-connector</artifactid>
<version>0.2</version>
</dependency>