Intelligent Mail barcode – iText and barcode4j

I use a java library called iText to create PDFs and do other PDF related tasks when I am building web applications, and i embed a lot of barcodes for various purposes. iText handles most of these very well, but I recently needed to replace the old USPS barcode (postnet) with the new barcode (intelligent mail). iText doesn’t support it, but with some helpful direction I implemented it using another library called barcode4j.  Here’s the method I wrote that you can pretty much copy and use directly:

/**
* Create a USPS Intelligent Barcode using Barcode4J and add it to iText document.
* @param code barcode value
* @param cb overcontent from stamper
* @param fieldPositions stamper.getAcroFields().getFieldPositions(“…”) for the placeholder field in PDF template
*/
public static void createUspsIntelligentBarcode(String code, PdfContentByte cb, float[] fieldPositions) {

if ((code.length() != 20) && (code.length() != 25) && (code.length() != 29) && (code.length() != 31)) {
throw new RuntimeException(“UspsIntelligentBarcode: code length of ” + code.length() + ” is invalid.”);
}

//Note: fieldPositions data = [page, llx, lly, urx, ury]
float height = (fieldPositions[4]-fieldPositions[2]);
float width = (fieldPositions[3]-fieldPositions[1]);

PdfTemplate tp = cb.createTemplate(width, height);

// Create the graphics and canvas objects that will contain the barcode.
Graphics2D g2 = tp.createGraphics(width, height);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.scale(2.5, 2.835); // (1mm == 2.835 points) + tweaking on x to make bar width correct
Java2DCanvasProvider provider = new Java2DCanvasProvider(g2, 0);

// Create Barcode4J barcode on canvas
USPSIntelligentMailBean barcode = new USPSIntelligentMailBean();
// use 70% of converted values.  Measurements on printouts needed to be tweaked.
barcode.setAscenderHeight(UnitConv.in2mm(0.1f) * 0.7f);  // height of ascender/descender per USPS spec
barcode.setTrackHeight(UnitConv.in2mm(0.05f)* 0.7f);      // height of track bar per USPS spec (smallest bar of barcode)
barcode.setBarHeight(UnitConv.in2mm(0.145f)* 0.7f);
barcode.setIntercharGapWidth(UnitConv.in2mm(0.04f)* 0.7f * 1.13f); // adjust again for scaling
barcode.generateBarcode(provider, code);

g2.dispose();

// adjust x/y to perfect location for envelope window
float inch = 72f; // itext manual pg 33
float xCoordinate = fieldPositions[1] – ((1f/8f) * inch);
float yCoordinate = fieldPositions[2] – ((3f/32f) * inch);

cb.addTemplate(tp, xCoordinate, yCoordinate);
}

This lets you put the intelligent mail barcode (or any barcode in barcode4j) directly into iText.  The key here is that the PdfTemplate in iText has a method that creates a generic Java Graphics2D object that is accessible for drawing by anything.  This generic object is exactly what is needed to be passed into the barcode4j canvas provider, and then any barcode4j barcode is output to the canvas.  A couple tweaks to position it however it is needed, and that is it.  It was a lot simpler than I expected when I realized I couldn’t just use iText for the whole thing.  Gotta love open source!

Advertisements

About mpickell

I'm a java developer View all posts by mpickell

4 responses to “Intelligent Mail barcode – iText and barcode4j

  • j.f. zarama

    very informative and helped me for work on a related project;

    should you have additional information and/or reference please forward or post since I’m having difficulty properly placing an address-lines and barcode on an 8 1/2 x 11 page for insertion on a No. 10 windowed envelope; thanks;

  • mpickell

    Do you have the iText manual? That is good reference for it. I have had trouble with the coordinates used in the library also.

    One key thing to remember is that the 0,0 coordinate is the bottom left corner of the page, not the upper left. So increasing the Y value is taking you from the bottom of the page to the top.

    Another trick that i have used a lot is to create a template using either Adobe Acrobat, or CutePdf Writer. Put a text field on the template where you want the address/barcode to be. You can then use something like this code:

    PdfStamper stamper = new PdfStamper( /* ...whatever... */);
    AcroFields form = stamper.getAcroFields();
    float [] fieldPositionsUsps = form.getFieldPositions("dpbcBarcode");

    to actual pull the position of the text field off of the template and use those coordinates (fieldPositionsUsps above) in the createUspsIntelligentBarcode method in this post. You never need to actually use the text field for anything other than its coordinates. I’m using this exact method in many places currently. It is just easier than trying to figure out the coordinates yourself.

  • Steve

    stumbled upon your article and thought you might be able to help. What jar files did you have to add to your webapp so barcode4j would work properly with iText? I added all the batik jars I could find but still get an error:

    2012-08-12 12:20:32,553 [http-bio-80-exec-1] ERROR org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/].[ReportServlet]- Servlet.service() for servlet [ReportServlet] in context with path [] threw exception [Filtered request failed.] with root cause
    java.lang.NullPointerException
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1593)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1523)
    at org.xml.sax.helpers.NewInstance.newInstance(NewInstance.java:49)
    at org.xml.sax.helpers.XMLReaderFactory.loadClass(XMLReaderFactory.java:187)
    at org.xml.sax.helpers.XMLReaderFactory.createXMLReader(XMLReaderFactory.java:180)
    at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(Unknown Source)
    at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(Unknown Source)
    at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(Unknown Source)
    at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createSVGDocument(Unknown Source)
    at net.sf.jasperreports.renderers.BatikRenderer.ensureSvg(BatikRenderer.java:181)

  • mpickell

    Well, this was quite a while ago… but i don’t recall adding any Batik jars.

    I recall this being quite simple. It was all iText, I added barcode4j so that I could use “USPSIntelligentMailBean”, and that was it I think. It was not anything extensive.

    The barcode4j barcode can be rendered to the provider. I believe the provider is either from the Java graphics library or from iText itself. That does the translation to something that iText can just drop into the PDF.

    So to summarize: I added barcode4j to get the “USPSIntelligentMailBean.” This was rendered to the provider basically turning it into a generic graphic that iText uses. iText never actually interacted with the barcode4j library except accepting the Java graphic that barcode4j produced.

    That exception doesn’t look related to add the barcode to the PDFTemplate.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: