Sometimes QR codes are a nice way to distribute information like calendar events, contact information, e-mail, geo-locations or internet addresses.
In the following article we’re going to encode information to QR code images using the ZXing library and afterwards decode information from a given QR code.
Finally we’re taking a look on online QR code generators and how to integrate the ZXing library in a Maven project.
The ZXing Library
-
Download the ZXing Libraries from http://code.google.com/p/zxing/downloads/list – the file name is ZXing-<version>.zip
-
Unpack the downloaded archive somewhere
-
Change to the extracted directory and run ant. If you don’t have JavaME installed – and you don’t have to for the samples below – run ant buildwithoutj2me – that will do the job
-
Having compiled the libraries you’re now free to include the core.jar from zxing-<version>/core/ and the javase.jar from zxing-<version>/javase as dependency in your project
Example
-
Main.java
package com.hascode.tutorial.qr_code; import java.io.File; public class Main { public static void main(String... args) { File imageFile = new File("/tmp/qr-code.png"); String input = "Visit hascode.com ;)"; // creating a qr code new QRCodeGenerator().generateQRcode(imageFile, input); // decoding the qr code from image String decoded = new QRCodeDecoder().decode(imageFile); System.out.println(decoded); } }
-
QRCodeGenerator.java
package com.hascode.tutorial.qr_code; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.ByteMatrix; import com.google.zxing.qrcode.QRCodeWriter; public class QRCodeGenerator { private int width = 400; private int height = 400; public void generateQRcode(File imageFile, String input) { ByteMatrix mtx = null; QRCodeWriter writer = new QRCodeWriter(); try { mtx = writer.encode(input, BarcodeFormat.QR_CODE, width, height); } catch (WriterException e) { return; } if (mtx != null) { BufferedImage image = MatrixToImageWriter.toBufferedImage(mtx); try { ImageIO.write(image, "png", imageFile); } catch (IOException e) { return; } } } }
-
QRCodeDecoder.java
package com.hascode.tutorial.qr_code; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import com.google.zxing.BinaryBitmap; import com.google.zxing.LuminanceSource; import com.google.zxing.Reader; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.QRCodeReader; public class QRCodeDecoder { public String decode(File imageFile) { BufferedImage image; try { image = ImageIO.read(imageFile); } catch (IOException e1) { return "io outch"; } // creating luminance source LuminanceSource lumSource = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource)); // barcode decoding Reader reader = new QRCodeReader(); Result result = null; try { result = reader.decode(bitmap); } catch (ReaderException e) { return "reader error"; } return result.getText(); } }
Running the example you should notice the generated png image in /tmp or the directory set – if you’ve got an android smart-phone you can test the image using this free app. The generated image should look something like this:
Legal Notice
QR Code is a registered trademark of Denso Wave Inc.
Troubleshooting
-
BUILD FAILED .. /usr/local/WTK2.5.2/lib not found. – run ant buildwithoutj2me instead of ant
-
If you encode byte arrays into QR codes you need to use ISO-8859-1 encoding instead of UTF-8 as workaround
-
If you’re getting a com.google.zxing.NotFoundException take a closer look at the produced QR code image – perhaps you have fallen victim to a strange bug in the matrix implementation in the ZXing library that produces an inverted image (black is white, white is black). If you wish to comment the bug – head over to the project’s bugtracker. If you’ve got an inverted image you need to invert the colors – using RescaleOp and RescaleOp.filter() didn’t work for me – so I coded some ugly workaround – all suggestions welcome :)
package com.hascode.tutorial.qr_code; [..] public class QRCodeGenerator { [..] public void generateQRcode(File imageFile, String input) { [..] if (mtx != null) { BufferedImage image = MatrixToImageWriter.toBufferedImage(mtx); image = invertImage(image); [..] } } private BufferedImage invertImage(BufferedImage image) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int rgb = image.getRGB(x, y); if (rgb == -16777216) { image.setRGB(x, y, -1); } else { image.setRGB(x, y, -16777216); } } } return image; } }
-
Here is a screenshot of the inverted image from the samples above
*update*__
Eric kindly noted that it is much easier to convert the bytes from the byte matrix directly – hey there are only two byte values to replace – so I have created this update to the QRCodeGenerator class:
package com.hascode.tutorial.qr_code;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
public class QRCodeGenerator {
private int width = 400;
private int height = 400;
public void generateQRcode(File imageFile, String input) {
ByteMatrix mtx = null;
QRCodeWriter writer = new QRCodeWriter();
try {
mtx = writer.encode(input, BarcodeFormat.QR_CODE, width, height);
} catch (WriterException e) {
return;
}
if (mtx != null) {
invertMatrix(mtx);
BufferedImage image = MatrixToImageWriter.toBufferedImage(mtx);
try {
ImageIO.write(image, "png", imageFile);
} catch (IOException e) {
return;
}
}
}
private void invertMatrix(ByteMatrix mtx) {
for (int w = 0; w < mtx.getWidth(); w++) {
for (int h = 0; h < mtx.getHeight(); h++) {
byte inverted = (byte) ((mtx.get(w, h) == 0x00) ? 0xFF : 0x00);
mtx.set(w, h, inverted);
}
}
}
}
Online Generators for QR Codes
If you want to create a QR code fast without coding there are some nice websites that help you creating the desired QR code images – e.g. the online generator from the ZXing project itself or Google Chart that offers support for QR codes.
There is also an online decoder offered from the ZXing project where you’re able to upload and test generated files.
Maven Repository
It’s a pity that zxing won’t be published on the central Maven repository – for discussion and more information please take a look at Issue 88.
Luckily for us Adam Gent helps us out by adding the libraries to his own repository as described in his article “http://adamgent.com/post/5510543597/added-zxing-to-my-own-maven-repo[Adding zxing to my own Maven repository]“.
This allows us to add the dependencies needed by adding the following repository and dependencies to your Maven project’s pom.xml
<repositories>
<repository>
<id>mvn-adamgent</id>
<url>http://mvn-adamgent.googlecode.com/svn/maven/release</url>
<name>Adam Gent Maven Repository</name>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>1.6</version>
</dependency>
</dependencies>