Generating Barcodes in PDFs with Flying-Saucer
Flying-Saucer is a nice library to generate PDF documents from within Java applications. Just generate a bunch of XHTML, throw it into the renderer and let it produce the desired document utilizing iText.
When it comes to barcodes however, Flying-Saucer cannot access the built in barcode functionality of iText (at least I didn’t find any documentation for it).
However, being OpenSource and well designed, one only needs to create one subclass to achieve the task: Flying-Saucer relies on a factory named ReplacedElementFactory, which can replace elements by custom objects. This is also used to embed images, as the class ITextReplacedElementFactory shows. Now we can simply create a subclass, which replaces images with an appropriate barcode:
<img src=’0123456789′ type=’code128′ style=’height: 1cm’ />
One simply needs to override the createReplacedElement method like this (the whole code can be found here: BarcodeReplacedElementFactory.java (GitHub)):
@Override public ReplacedElement createReplacedElement( LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) { Element e = box.getElement(); if (e == null) { return null; } String nodeName = e.getNodeName(); if (nodeName.equals("img")) { if ("code128".equals(e.getAttribute("type"))) { try { Barcode128 code = new Barcode128(); code.setCode(e.getAttribute("src")); FSImage fsImage = new ITextFSImage( Image.getInstance( code.createAwtImage( Color.BLACK, Color.WHITE ), Color.WHITE )); if (cssWidth != -1 || cssHeight != -1) { fsImage.scale(cssWidth, cssHeight); } return new ITextImageElement(fsImage); } catch (Throwable e1) { return null; } } } return super.createReplacedElement( c, box, uac, cssWidth, cssHeight); }
Granted, ‘type’ is no valid XHTML-Element for <img /> but as you can see in the code above, you could easily replace it with data-type or any other attribute. Flying-Saucer doesn’t seem to care about this anyway.
Note: The code above can only handle Code128-Barcodes, but can easily be extended to handle EAN and the like (iText supports a whole bunch of barcodes by default).
In order to make our factory work, we need to pass it to the renderer – which is pretty darn easy:
ITextRenderer renderer = new ITextRenderer(); renderer.getSharedContext().setReplacedElementFactory( new BarcodeReplacedElementFactory( renderer.getOutputDevice() )); renderer.setDocumentFromString(inputAsString); renderer.layout(); renderer.createPDF(outputAsStream);
Reference: Generating Barcodes in PDFs with Flying-Saucer from our JCG partner Andreas Haufler at the Andy’s Software Engineering Corner blog.