Android Tips #41 ZXing ライブラリ (2.1) を使って QR コードを読み取る
ZXing ライブラリとは
ZXing ("Zebra Crossing"と呼ぶ) はバーコードをアプリ内で読み取るためのオープンソース・ライブラリです。Google が提供しています。このライブラリを使うと1次元バーコードと2次元バーコード (QRコード) を画像から簡単に読み取ることができます。Android だけではなく iOS 用や ActionScript 用などさまざまなプラットフォーム向けのライブラリが提供されています。
QR コードを読み取るアプリのほとんどが ZXing ライブラリを使っているといっても過言ではないでしょう。Android アプリでは「QRコードスキャナー」という有名なアプリがありますが、もちろんこのライブラリを使って実装されています。
今回はそんな ZXing ライブラリを使って QR コードを読み取るアプリを実装してみたいと思います!
今回つくるアプリの機能
今回つくるアプリの機能は以下のような感じです。
- カメラを起動し、プレビューを表示する
- 画面をタップしてオートフォーカスさせる
- QRコードを読み取る
- 読み込み結果をトーストで表示
QRコードを読み取るタイミングですが、今回は分かりやすく画面をタップしてオートフォーカスされたあとにしてみました。
ZXing ライブラリを導入する
はじめに ZXing ライブラリをアプリプロジェクトにインポートしましょう。まずは以下のダウンロードサイトにアクセスします。
http://code.google.com/p/zxing/downloads/list
ダウンロードしてきた zip ファイルを解答して以下のファイルをコピーします。
- core/core.jar
- javase/javase.jar
コピーしたファイルは android プロジェクトの libs フォルダにつっこみます。
以上で事前準備は完了です!
なお、以前のバージョンは PlanarYUVLuminanceSource をサンプルプロジェクトから移植してこないといけなかったり、いろいろ面倒だったみたいですが、現在のバージョンは非常に簡単に実装できるようになっているようでした。
カメラでプレビューを表示する(おさらい)
まずはじめにカメラを起動してプレビューを表示するところを実装します。カメラのプレビューは以前の記事で執筆していますので、そちらも参照してください。
Android Tips #16 カメラプレビューで顔を検出する
まずは AndroidManifest.xml を編集し、カメラのパーミッションを許可します。
<uses-permission android:name="android.permission.CAMERA" />
あとはカメラプレビューを Activity に実装します。画面タップでオートフォーカスし、オートフォーカス完了後にプレビューをデータに変換するところまでの実装です。ここまではサクサクといきましょう。
CameraPreviewActivity.java
package jp.classmethod.android.sample.barcodescanner; import java.util.List; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.AutoFocusCallback; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.Size; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; public class MainActivity extends Activity { private SurfaceView mSurfaceView; private Camera mCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSurfaceView = new SurfaceView(this); mSurfaceView.setOnClickListener(onClickListener); setContentView(mSurfaceView); } @Override protected void onResume() { super.onResume(); SurfaceHolder holder = mSurfaceView.getHolder(); holder.addCallback(callback); } private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { // 生成されたとき mCamera = Camera.open(); try { // プレビューをセットする mCamera.setPreviewDisplay(holder); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 変更されたとき Camera.Parameters parameters = mCamera.getParameters(); List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); Camera.Size previewSize = previewSizes.get(0); parameters.setPreviewSize(previewSize.width, previewSize.height); // width, heightを変更する mCamera.setParameters(parameters); mCamera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 破棄されたとき mCamera.release(); mCamera = null; } }; private OnClickListener onClickListener = new OnClickListener() { @Override public void onClick(View v) { // オートフォーカス if (mCamera != null) { mCamera.autoFocus(autoFocusCallback); } } }; private AutoFocusCallback autoFocusCallback = new AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { // 現在のプレビューをデータに変換 camera.setOneShotPreviewCallback(previewCallback); } } }; private PreviewCallback previewCallback = new PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { // TODO バーコード読み取り } }; }
ZXing の使いかた
次にいよいよ QR コードを読み取る部分の実装です。PreviewCallback.onPreviewFrame() 内にプレビューのデータからバーコードを読み取る処理を実装します。読み取り完了後、データを Toast で出力しています。
private PreviewCallback previewCallback = new PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { // 読み込む範囲 int previewWidth = camera.getParameters().getPreviewSize().width; int previewHeight = camera.getParameters().getPreviewSize().height; // プレビューデータから BinaryBitmap を生成 PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource( data, previewWidth, previewHeight, 0, 0, previewWidth, previewHeight, false); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); // バーコードを読み込む Reader reader = new MultiFormatReader(); Result result = null; try { result = reader.decode(bitmap); String text = result.getText(); Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show(); } catch (Exception e) { Toast.makeText(getApplicationContext(), "Not Found", Toast.LENGTH_SHORT).show(); } } };
ここで出てくる PlanarYUVLuminanceSource ですが、これは読み取る対象のデータの範囲などを設定するクラスです。引数は以下の様な感じです。
第一引数 | byte[] | byte 配列の YUV 画像データ (プレビューのデータ) |
---|---|---|
第二引数 | int | 画像データの width |
第三引数 | int | 画像データの height |
第四引数 | int | 画像データのうち、読み取りの開始 X 座標 |
第五引数 | int | 画像データのうち、読み取りの開始 Y 座標 |
第六引数 | int | 画像データのうち、読み取る width |
第七引数 | int | 画像データのうち、読み取る height |
第八引数 | boolean | 画像データを反転するか否か (フロントカメラの場合は true) |
以上でひとまず動作します。 QR コードをカメラで移してタップすると読み取り結果が Toast で表示されると思います!
今回は簡単なサンプルなので、カメラのプレビューから QR コードを読み取る範囲の設定などは特に行なっていません。「矩形の範囲内だけ読み取る」といった実装にすると読み取り精度がより安定し、処理速度も上がると思います。読み取り結果が表示されるまで時間がかかる場合は、QR コードを画面いっぱいに表示するか、画面上がモノクロになる状態で読み取ってみてください。
なお QR コード作成は以下のサイトを使わせていただきました。素晴らしいサービスありがとうございます!
まとめ
ZXing を使うと QR コードの読み込みがとっても簡単に実装できます!ぜひ活用していきたいですね。でも何より一番大事なのはこの技術を使って何を作るかですよね。つまり URL や メールアドレス、ネットショッピングの決済情報…そんなデータが手軽に取れるということです!ここからはアイデア次第ですが、技術をふんだんに活用し、面白いアプリを作りましょう!
QR コード作成についてはまた別のエントリでご紹介したいと思います。
ところで QR コードの QR って Quick Response の略らしいです。知りませんでした…。