Wednesday, December 19, 2012

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: (GitHub)):

    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();
                    FSImage fsImage = new ITextFSImage(



                    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();
                new BarcodeReplacedElementFactory(