Friday, January 14, 2011

QR-Codes with GlassFish and PrimeFaces


I've been playing around with QR-Codes lately. To make it short. I love them. If you have a nice, little reader on your mobile you have a very handy way of getting contacts, urls, email adresses, and short texts into your mobile. If you look around, you can find a lot of websites offering to create such stuff for you.
One of the most prominent are the Google Chart Tools. If you like to, you can simply use this online version. An image tag with the following url
https://chart.googleapis.com/chart?
chs=150x150&cht=qr&
chl=Hello%20world&choe=UTF-8
gives you a very simple "Hello World" QR-Code. But what happens if you are not able or willing to access any free service on the net? What happens if you need to create your own QR Codes? Here we go. That was part of the question I was asking myself. And here is a short howto.

Getting started
Make yourself comfortable with whatever programming language you want to use. But for this tutorial you are going to need a Java EE Webcontainer or at best one of the latest GlassFish 3.x. Next is to grep your copy of Primefaces and one of your favorite development environments. If you are naughty you could also use the latest NetBeans 7.0 Beta which provides all prerequisites out of the box.
Start by creating a new web-project and make sure to check the box beside "Enable Context and Dependency Injection" and also make sure you use the JSF 2.0 implementation with PrimeFaces as the component library. If this is done, you have to make a decision for the QR-Code library to use. I did a simple search on google and was somehow disappointed. Many many options but mostly readers or even closed source. One very promising result was ZXING. ZXing (pronounced "zebra crossing") is an open-source (Apache v2), multi-format 1D/2D barcode image processing library implemented in Java. If you look at the samples you mostly find decoding samples. But there also is an Encoder.
That's what I was looking for. Get the 1.6 release which has roughly 60 MB and start by unpacking it. Next is to build the core project (mvn install). Which gives you a handy (325KB) core-1.6-SNAPSHOT.jar to copy as a library to your netbeans project. Now your all set and we can start coding.

Encoding Strings
Wow. That is not too easy. Even if there is an Encoder, you still have to do some work to get this done. If you look around the google groups discussions forum you quickly find some solutions. One came up with a complete generateQRCodeImage() Method which you can simply copy and use for your own trials.
The basic magic is to not only have the simple QR-Code written but also have the "the quiet zone" as described in QR code spec (at least 4 modules on each size). So here is all you have to do:

QRCode qrcode = new QRCode();
Encoder.encode(code, ErrorCorrectionLevel.L, qrcode);

Plus all the magic you need for having "the quiet zone" in place (please refer to the mentioned method above for a complete walthrough). After that you simply have to write out to whatever stream you need.

ImageIO.write(image, "png", out);


Putting it into a Servlet
The simplest approach is to encapsulate everything into a servlet. All you need is an OutputStream to which to write your QR-Code:

generateQRCodeImage(out, code, width, width);

If you add some magic parameters you can even have you own @WebServlet(name = "QRCodeGenerator").

Primefaces are better
But who wants to use Servlets our days? JSF 2.0 and Primefaces are the ones to use. All you need is the Dynamic Image Streaming component from Primefaces. Use the example and put your generateQRCodeImage method into that managed bean.

@Named(value = "qrcontroller")
public class QrImageController

Small difference, you now have to use the StreamedContent API for getting the image data. You have to play around a bit to find a solutions. The fastest way was to simply get an ByteArrayInputStream and convert it to a DefaultStreamedContent. That worked. Even if you have some additional steps for converting the BufferedImage. Finally all you have to do is to put the component to your facelet

<p:graphicimage value="#{qrcontroller.qrcode}"></p:graphicimage>

Right click your project, select run and you are done!
Fine! Thanks for reading! If you have comments or other libraries you can recommend: I would be happy to read about what you are thinking.