Android+ZxingでQRコード操作

手持ちのXperiaが、初期型によくある充電部分の接触不良を発動させて泣きたいアシアです。
今は会社の先輩が機種変したため使わなくなったXperiaを借りてなんとかしのぎ中。
それはともかく、Android開発の仕事にはついていないのですが、
仕事があまりにもひm…勉強兼ねて、
先輩にお題を出してもらってAndroidアプリを作ってみました。
アプリの内容はさておき、Zxingを使ったのでそのメモ。
解説サイトはさほど多くはありませんが、その代わりどこも丁寧に解説してくれてるので、
似たり寄ったりな記事になりそうだ…。

開発環境

Android開発環境

これがないと始まらないけど、ここでは割愛。
EclipseとAndroid端末を使って、
デバッグ実行できる環境を作ってあることを前提にします。

Zxing(ゼブラクロッシング)

1~2次元バーコードのエンコードやデコードをサポートするJavaライブラリ。
以下から最新版zipをダウンロードし、任意な場所に展開するだけでOK。
2.0が最新のようです。
http://code.google.com/p/zxing/downloads/list/

Ant

Zxingの解凍先に下記2つがあれば不要。2.0では不要でした。

Zxing解凍先\core\core.jar

Zxing解凍先\javase\javase.jar

導入は以下からダウンロードし、任意な場所に展開の上、環境変数のPATHにbinへのパスを通すだけです。

http://ant.apache.org/bindownload.cgi

パスを通したら、コマンドプロンプトから、Zxing解凍先\core と Zxing解凍先\javase にそれぞれ移動して、

ant

を実行すればcore.jarとjavase.jarを作成できます。

プロジェクトに追加

利用したいプロジェクトのワークスペース\libs(無ければ作る)に先程のcore.jarとjavase.jarをぶち込めば準備はOK!

サンプルを動かしてみる

開発の前に、Zxingには有名なバーコードリーダーのソースも含まれているので、動かし方だけ。
ソースコードも追いかけてみましたが、バーコードの読込部分以外はいろんな意味で複雑怪奇!
コマンドプロンプトから下記コマンドを実行します。

cd Zxing解凍先\android\
del build.xml
android update project -p . -t TargetID

TargetIDについては、同じくコマンドプロンプトから、

android list targets

を実行し、各々の開発環境に応じたID番号を選択して下さい。
AndroidManifest.xmlから以下を削除。

<manifest android:installLocation="auto">
<supports-screens android:xlargeScreens="true">

あとはZxing解凍先\androidを一式Eclipseに取り込み、libsフォルダを作成、core.jarとjavase.jarをぶち込めば実行できます。
@overrideでエラーが出る場合は、Java SDKのバージョンを1.6にします。
Package Explorerから[CaptureActivity]を選択し、右クリック
[Properties]->[Java complier]
[Enable project specific settings]にチェック
[Complier compliance level]に[1.6]を選択
[OK]

QRコード作ってみる

QRCodeWriter.encodeを利用すると、QRコードのbitデータが返却されます。
ここでは引数に渡されたバイナリデータqrDataを格納したQRコードを作成しています。

public class QRCodeControler {

    /// エンコード設定
    private static final String ENCORD_NAME = "ISO-8859-1";

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Bitmap createQRCode(byte[] qrData){

        Bitmap ret = null;

        try
        {
            // QRコードを生成するにあたり、バイナリデータをStringへ変換
            String contents = new String(qrData, ENCORD_NAME);

            // QRコードを生成
            QRCodeWriter writer = new QRCodeWriter();
            Hashtable encodeHint = new Hashtable();
            encodeHint.put(EncodeHintType.CHARACTER_SET, ENCORD_NAME);
            encodeHint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            BitMatrix bitData = writer.encode(contents, BarcodeFormat.QR_CODE, 350, 350, encodeHint);
            int width = bitData.getWidth();
            int height = bitData.getHeight();
            int[] pixels = new int[width * height];
            // All are 0, or black, by default
            for (int y = 0; y < height; y++) {
                int offset = y * width;
                for (int x = 0; x < width; x++) {
                    pixels[offset + x] = bitData.get(x, y) ? 0xFF000000 : 0xFFFFFFFF;
                }
            }

            // Bitmapに変換
            ret = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            ret.setPixels(pixels, 0, width, 0, 0, width, height);
            return ret;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }
}

QRコード読んでみる

QRCodeReader.decodeを利用すると、Resultに読み込み結果が格納され、
QRコードが見つからない場合はNotFoundExceptionをthrowします。
decodeにQRコードを渡す場合、BinaryBitmapインスタンスに加工する必要があります。
今回は、こちらを丸々コピーしてきて加工はお任せしています。

Zxing解凍先\androidtest\src\com\google\zxing\client\androidtest\RGBLuminanceSource.java

public class QRCodeControler {

    /// エンコード設定
    private static final String ENCORD_NAME = "ISO-8859-1";

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public byte[] ReadQRCode(byte[] data){
        try
        {

            // Bitmapを作成する
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

            // Bitmap内からQRコードを探索する
            LuminanceSource source = new RGBLuminanceSource(bitmap);
            Hashtable decodeHint = new Hashtable();
            decodeHint.put(DecodeHintType.CHARACTER_SET, ENCORD_NAME);
            decodeHint.put(DecodeHintType.TRY_HARDER, true);
            BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
            Reader reader = new QRCodeReader();
            Result result = reader.decode(binaryBitmap, decodeHint);

            // 探索結果から文字列を抽出し、byte配列に変換 
            byte[] dataByte = result.getText().getBytes(ENCORD_NAME);
            return dataByte;
        }
        catch (Exception e)
        {
            return null;
        }
    }
}

おまけ(カメラと連携)

カメラで撮影したデータを渡す場合、カメラデータはYUV形式だと聞いたので、 こちらを利用しています。

zxing解凍先\android\src\com\google\zxing\client\android\PlanarYUVLuminanceSource.java

なお、カメラと連動するときは、シャッターをきらずに常にオートフォーカス→QRコード検出とした方が認識率から見てもUI的にもいいですね。
ちなみにRGBLuminanceSourceだと、Zxingに作ってもらったQRコードにもかかわらず認識できないケースが発生しました。
なにがなにやら?

2018/8/20追記

6年後、再び同じことするとは…使い方とか微妙に変わってますね。 


他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

1件のコメント

返信を残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)