この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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 の略らしいです。知りませんでした…。