Java

ZXingを使ってQRコードの生成/読み取りを行う

URLやSNSのIDなど、さまざな情報を共有できる手段として QRコード は浸透してきました。人間にはそのQRコードに格納された情報を理解することは困難ですが、生成や読み取りを行うプログラムは簡単にできるようになりました。本稿では、ITFバーコードやQRコードなどの各種バーコードを生成できる Java のライブラリ ZXing でQRコードを生成/読み取りする方法について解説します。

こんな人におすすめ
  • QRコードから情報を読み出したい
  • QRコードによって情報共有を行うアプリを作りたい
  • キャッシュレス決済ごっこに使いたい

ZXingとは

ZXing(ゼブラクロッシング)は、Javaで実装されたオープンソースのマルチフォーマット1次元・2次元コード画像処理ライブラリであり、.NETやC++など様々な言語の移植やバインディングが展開されています。

2次元コードについては以下がサポートされています(2019年9月現在)

QRコードマトリクス型2次元コード。大きな情報量、誤り訂正機能といった二次元コードの特徴に加え、二次元コードの弱点だった読み取り性能においても非常に優れた二次元コードです。また、日本のデンソーウェーブで開発された二次元コードのため、漢字、カナ、ひらがなの情報を効率よく情報を収納できます。
DataMatrixコードマトリクス型2次元コード。情報密度が非常に高く、誤り訂正率も高いことから、アメリカでは部品のマーキングに使用されています。
Aztecコードマトリクス型2次元コード。チケット販売所やレンタカー会社で使用されています。Aztec コードの名前は、中央のファインダーコードがアツテカ文明のピラミッドを上から見た形と似ていることに由来しています。
PDF 417スタック型2次元コード。主にアメリカ合衆国で身分証明書をはじめ様々な用途で使用される。日本国内では日本自動車工業会で採用されており、EDIデータ付き現品ラベルなどで使われています。
MaxiCodeマトリクス型2次元コード。貨物の仕分けや追跡のために、アメリカの宅配業者によって開発されたコードです。物流分野において高く評価されています。読み取り専用。
GS1 DataBar Omnidirectional (RSS-14)マトリックス型2次元コードとの合成シンボルも使用されている形式のため、2次元コードのサポートととして分類されています。新しい符号化理論を用いており、EAN(JAN)、UPCシンボルと比較すると、同じ量のデータをより小さいスペースで表現できるという特徴があります。日本国内では、2006年の厚生労働省の通知によって、医療用医薬品の包装にバーコードGS1データバーとGS1-128が表示されるようになりました。読み取り専用。
GS1 DataBar Expanded (RSS-Expanded)GS1 Databar Expanded(拡張型)は補足情報もエンコードできるシンボルです。RSS-14とともに2次元コードのサポートとして分類されています。読み取り専用。

セットアップ

ZXingはGithubのページ https://github.com/zxing/zxing ではjarが配布されていません。ソースからビルドするのが難しい場合は、Mavenのリポジトリよりダウンロードするのをおすすめします。core-*.*.*.jarとjavase-*.*.*.jarをクラスパスに追加してください(PCの場合です。Androidの場合はjavaseではなくandroid-coreが必要です)。

https://repo1.maven.org/maven2/com/google/zxing/core/3.4.0/core-3.4.0.jar

https://repo1.maven.org/maven2/com/google/zxing/javase/3.4.0/javase-3.4.0.jar

Mavenを使用する場合は、pom.xmlに以下の定義を追加してください。

pom.xml

<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.4.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.4.0</version>
</dependency>

サンプルソース

基本

生成処理

以下のソースはQRCodeWriterwを使って、URL「http://develman.net」をQRコードにエンコードして、「qrcode.png」という画像ファイルに出力するサンプルです。以降の生成処理の解説のベースとしています。

Java

package net.develman.barcode;

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

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ZxingQRWriterExample {

    public static final void main(String[] args) {
        String content = "https://develman.net";
        int width = 200;
        int height = 200;
        String output = "qrcode.png";

        try {
            QRCodeWriter qrWriter = new QRCodeWriter();

            //QRCodeWriter#encode()には以下の情報を渡す
            // (1)エンコード対象の文字列、バーコードに埋め込みたい情報
            // (2)出力するバーコードの書式
            // (3)イメージの幅
            // (4)イメージの高さ
            BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height);

            BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);

            //エンコードで得られたイメージを画像ファイルに出力する
            ImageIO.write(image, "png", new File(output));

        } catch (WriterException e) {
            System.err.println("[" + content + "] をエンコードするときに例外が発生.");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("[" + output + "] を出力するときに例外が発生.");
            e.printStackTrace();
        }
    }
}

上のコードを実行すると画像ファイルとして得ることができます。

スマートフォンのQRリーダー等で読み込むと、URIとして認識されると思います。実際、QRコード生成時にテキストしかエンコードできませんが、読み込み側でプロトコルから判別しています。

読み取り処理

以下のソースはQRCodeReaderを使って、「qrcode.png」という画像ファイルをデコードしてURL「http://develman.net」を読み取るサンプルです。以降のパターンに共通で使えます。

Java

package net.develman.barcode;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DetectorResult;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.oned.EAN13Reader;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.detector.Detector;
import com.google.zxing.qrcode.encoder.QRCode;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ZxingQRReadExample {

    public static final void main(String[] args) {
        String input = "qrcode.png";

        try {
            //画像データを読み込む
            BufferedImage image = ImageIO.read(new File(input));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap bitmap = new BinaryBitmap(binarizer);

            QRCodeReader reader = new QRCodeReader();

            //QRCodeReader#decode()には以下の情報を渡す
            // (1)読み込んだイメージ
            Result result = reader.decode(bitmap);

            System.out.println(result.getText());

        } catch (NotFoundException e) {
            System.err.println("[" + input + "] イメージの中にバーコードが見つからないためデコードで例外が発生.");
            e.printStackTrace();
        } catch (ChecksumException e) {
            System.err.println("[" + input + "] バーコードが見つかったがチェックサム検査で例外が発生.");
            e.printStackTrace();
        } catch (FormatException e) {
            System.err.println("[" + input + "] は書式不正のためデコードで例外が発生.");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("[" + input + "] を読み込むときに例外が発生.");
            e.printStackTrace();
        }
    }
}

実行結果

https://develman.net

Eメールアドレスを埋め込む

生成処理

mailto:をメールアドレスの前に付加します。

Java

String content = "mailto:sample@develman.net";
int width = 200;
int height = 200;
String output = "qrcode_email.png";

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));

読み取り

実行結果

mailto:sample@develman.net

電話番号を埋め込む

tel:と国番号を電話番号の前に付加します。電話番号の頭の0は除外します。

生成処理

Java

String content = "tel:+81312345678";
int width = 200;
int height = 200;
String output = "qrcode_tel.png";

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));

読み取り

実行結果

tel:+81312345678

連絡先(vCard)を埋め込む

vCard形式で文字列を作成します。日本語をはじめとするマルチバイト文字を入れる場合は、encodeの引数にエンコードヒントを追加してください。

生成処理

Java

int width = 200;
int height = 200;
String output = "qrcode_vcard.png";

String[] vcardElements = {
        "BEGIN:VCARD",
        "VERSION:4.0",
        "N:ささきゆ;たろう",
        "FN:たろう ささきゆ",
        "BDAY:19700101",
        "TEL;HOME;VOICE:(03) 1234-5678",
        "URL:https://develman.net",
        "END:VCARD"};
String content = String.join("\n", vcardElements);

Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));

読み取り

実行結果

BEGIN:VCARD
VERSION:4.0
N:ささきゆ;たろう
FN:たろう ささきゆ
BDAY:19700101
TEL;HOME;VOICE:(03) 1234-5678
URL:https://develman.net
END:VCARD

カレンダーイベントを埋め込む

iCalendar(vCalendar)形式で文字列を作成します。日本語をはじめとするマルチバイト文字を入れる場合は、encodeの引数にエンコードヒントを追加してください。

生成処理

Java

int width = 200;
int height = 200;
String output = "qrcode_event.png";

String[] icalendarElements = {
        "BEGIN:VEVENT",
        "SUMMARY:夏祭り",
        "DTSTART:20190820T150000Z",
        "DTEND:20190820T210000Z",
        "END:VEVENT"
};
String content = String.join("\n", icalendarElements);

Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));

読み取り

実行結果

BEGIN:VEVENT
SUMMARY:夏祭り
DTSTART:20190820T150000Z
DTEND:20190820T210000Z
END:VEVENT

WiFi接続情報を埋め込む

形式はWIFI:T:WPA;S:mynetwork;P:mypass;H:です。

T認証タイプ。WEPまたはWPA
SネットワークSSID
Pパスワード
Hオプション。ネットワークSSIDが非表示の場合はTrue。

生成処理

Java

String content = "WIFI:T:WPA;S:7SPOT;;;";
int width = 200;
int height = 200;
String output = "qrcode_wifi.png";

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));

読み取り

実行結果

WIFI:T:WPA;S:7SPOT;;;

エラー訂正レベルを設定する

エンコードヒントを設定することでエラー訂正レベルを設定できます。デフォルトはLです。訂正レベルをあげるとシンボルの密度が上がり、より複雑になります。折れや汚れの耐性が必要な状況では、訂正レベルを上げてください。

エラー訂正レベル L7%
エラー訂正レベル M15%
エラー訂正レベル Q25%
エラー訂正レベル Hこ30%

生成処理

Java

String content = "https://develman.net";
int width = 200;
int height = 200;
String output = "qrcode_correct_l.png";

Hashtable hints = new Hashtable();

//4段階のエラー訂正率を設定できます
//ErrorCorrectionLevel.L
//ErrorCorrectionLevel.M
//ErrorCorrectionLevel.Q
//ErrorCorrectionLevel.H
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
ImageIO.write(image, "png", new File(output));
エラー訂正レベル L
エラー訂正レベル M
エラー訂正レベル Q
エラー訂正レベル H
ABOUT ME
sasakiyu
ひ弱で優しい少年だったが、デーモンと合体。 強大な力を得つつも人間の心を失わないデベルマンとなる。