Playing around with QR Codes

May 11th, 2010 by

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 “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>

Resources

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) == 0×00) ? 0xFF : 0×00);
mtx.set(w, h, inverted);
}
}
}
}

Tags: , , , , , , , ,

5 Responses to “Playing around with QR Codes”

  1. eric Says:

    I ran into the inversion problem, too, and found it a bit simpler to re-invert the ByteMatrix returned by the Writer (only having to deal with 0×0 and 0xff).

  2. mk Says:

    Thanks for the remark! It is indeed simpler to invert the byte matrix .. I have updated the article with a corresponding example

  3. Jake Says:

    Looking for elegant solution to decode an inverse color scheme in an ECC200 2D data matrix. Inverse schemes are used widely in my community. I’m using ZXing Image Decoder API to get raw bytes. Works well with standard scheme. Not with inverse. Have read several comments on different issues. Your’s seems most cogent. Ideas?

  4. Tasneem hyder Says:

    I tried to generate calendar event qr code using Google ZXing API but the image generated by it is not recognisable as an event. I used the same data format specified at different websites but it only creates qr code but not as a recognizable event. BEGIN:VEVENT SUMMARY:Concert DTSTART:20110912 DTEND:20110912 DESCRIPTION:Metallica concert END:VEVENT Can you please tell me what I am missing. Only for calendar event.

  5. micha kops Says:

    Something like this did not work?

    BEGIN:VEVENT
    SUMMARY:Test Event
    DTSTART:20140507T223400Z
    DTEND:20140508T233400Z
    END:VEVENT

    You may use the zxing online generator here:
    http://zxing.appspot.com/generator/

Search
Categories