JavaでQRコードを作る・読む「ZXing」

バーコードやQRコードの二次元コードのエンコード・デコード処理を実装した「ZXing(ゼブラ・クロッシング)」というオープンソースのJavaのライブラリを使った、簡単なQRコードの作成と読み取りを行うJavaサンプルを紹介します。
ZXingは次のGitHubから入手できます。
ここからコンパイルしなくても、jarファイルがMavenのリポジトリから提供されています。core-x.x.x.jarと、javase-x.x.x.jarをダウンロードしてください(この時点では3.5.0が最新でした)。

簡単なQRコードの作成(エンコード)

QRコードを生成する最も簡単な例です。QRCoreWriteクラスのencodeメソッドによりQRコードを生成し、png画像に出力します。
zxtest_enc1.java
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

public class zxtest_enc1 {

    public static void main(String[] args) {
        try {
            QRCodeWriter qw = new QRCodeWriter();
            BitMatrix bm = qw.encode("ZXing QR code", BarcodeFormat.QR_CODE, 200, 200);
            BufferedImage img = MatrixToImageWriter.toBufferedImage(bm);
            ImageIO.write(img, "png", new File("zxtest.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
次のようにコンパイルし、実行します。
    javac -classpath core-3.5.0.jar:javase-3.5.0.jar zxtest.java
    java -classpath core-3.5.0.jar:javase-3.5.0.jar: zxtest 
-classpathは「:」で区切って複数指定できます。Windowsの場合は「;」で区切ります。
文字列「ZXing QR code」を記録したQRコード画像「zxtest01.png」が出力されます。画像をスマートフォンなどで読み取ると、「ZXing QR code」が記録されていることが確認できるはずです。
Picture

encodeメソッドの引数は次の通りです。
String contents QRコードの文字列データ
BarcodeFormat format BarcodeFormat.QR_CODE(QRコードを指定)
ZXingはバーコードもサポートしている
int width, height 画像サイズ(ピクセル)
通常は正方形で指定する
この例では、バージョンや誤り訂正レベルを指定していません。その場合は、最適なバージョンが自動的に割り当てられ、誤り訂正は最低レベル「L」が適用されます。
上の例の画像データのファイル出力部分は、j2seパッケージのMatrixToImageWriterクラスを使えば更に簡単に実装できます。出力結果は上と同じです。
zxtest_enc2.java
import java.io.*;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

public class zxtest_enc2 {

    public static void main(String[] args) {
        try {
            QRCodeWriter qw = new QRCodeWriter();
            BitMatrix bm = qw.encode("ZXing QR code", BarcodeFormat.QR_CODE, 200, 200);
            MatrixToImageWriter.writeToFile(bm, "png", new File("zxtest.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

デコード

次は、QRコードを含む画像ファイル(zxtest.png)を読み取り、内容を文字列とバイトデータで表示します。QRCodeReaderクラスのdecodeメソッドによりQRコードをデコードします。
zxtest_dec1.java
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
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 zxtest_dec1 {

    public static void main(String[] args) {
        try {
            BufferedImage img = ImageIO.read(new File("zxtest.png"));
            LuminanceSource src = new BufferedImageLuminanceSource(img);
            Binarizer bin = new HybridBinarizer(src);
            BinaryBitmap bm = new BinaryBitmap(bin);

            QRCodeReader qrr = new QRCodeReader();
            Result result = qrr.decode(bm);
            String tdata = result.getText();
            System.out.println(tdata);
            byte[] bdata = tdata.getBytes();
            for (byte d: bdata)
                System.out.printf("%02x ", d);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
次のように読み取ったデータの内容が表示されます。
ZXing QR code
5a 58 69 6e 67 20 51 52 20 63 6f 64 65

誤り訂正・バージョンを指定してエンコード

encodeメソッドには、Mapでエンコードのオプションを追加して与えることができます。最初の例のencodeメソッドの末尾にMapを設定するもう一つのencodeメソッドを使います。
zxtest_enc3.java
import java.io.*;
import java.util.*;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.EncodeHintType;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class zxtest_enc3 {

    public static void main(String[] args) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);     // L, M, Q, H 
            hints.put(EncodeHintType.MARGIN, 2);                                    // マージンのセル数
            hints.put(EncodeHintType.QR_VERSION, 3);                                // バージョン

            QRCodeWriter qw = new QRCodeWriter();
            BitMatrix bm = qw.encode("ZXing QR code", BarcodeFormat.QR_CODE, 200, 200, hints);
            MatrixToImageWriter.writeToFile(bm, "png", new File("zxtest.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Picture

マップのキーにenum EncodeHintTypeの種別を指定し、それぞれ設定します。
EncodeHintType.ERROR_CORRECTION 誤り訂正レベル ErrorCorrectionLevel.L
ErrorCorrectionLevel.M
ErrorCorrectionLevel.Q
ErrorCorrectionLevel.H
EncodeHintType.MARGIN 外側のマージン(余白)のセル数 1〜
EncodeHintType.QR_VERSION バージョン 1〜40
EncodeHintType.CHARACTER_SET 文字コード名 "Shift_JIS"
StandardCharsets.UTF_8

日本語を含むエンコード

データに日本語を含む場合は、hintsに文字コードセットを指定します。QRコードの規則で日本語はシフトJISとされています。
zxtest_enc4.java
import java.io.*;
import java.util.*;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.EncodeHintType;

public class zxtest_enc4 {

    public static void main(String[] args) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "Shift_JIS");
            QRCodeWriter qw = new QRCodeWriter();
            BitMatrix bm = qw.encode("日本語ABC012", BarcodeFormat.QR_CODE, 200, 200, hints);
            MatrixToImageWriter.writeToFile(bm, "png", new File("zxtest.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Picture

バイナリデータのエンコード

QRCodeWriterクラスのencodeメソッドへ与えるデータはString型ですが、バイト型配列をStringに変換することでバイナリデータが格納ができます。
zxtest.java
import java.io.*;
import java.util.*;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

public class zxtest {

    public static void main(String[] args) {
        try {
            QRCodeWriter qw = new QRCodeWriter();
            byte[] data = {0x01, 0x02, 0x00, 0x04, 0x05}; 
            BitMatrix bm = qw.encode(new String(data), BarcodeFormat.QR_CODE, 200, 200);
            MatrixToImageWriter.writeToFile(bm, "png", new File("zxtest.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Picture