KXABarcodeReader Programmer's Guide (Android)

2019-08-05/2022-02-20

このページではバーコード認識(デコーダ)ソフトウェア「KXABarcodeReader Library Android版」の使用方法を解説します。

Android版KXABarcodeReader LibraryはAndroidライブラリ形式 (.aar) ファイルで提供されます。ライブラリファイル名は「kxabarcodereader.aar」です。

kxabarcodereader.aar

KXABarcodeReader Libraryを利用したいアプリのAndroid Studioプロジェクト内に kxabarcodereader.aar をコピーし、Project Structureに依存関係を追加してください。

KXABarcodeReaderのコア部分はC/C++で記述されていますが、Android向けのAPIとしてはJNIによるネイティブメソッドを実装したJavaクラスを使用します。

KXABarcodeReaderの仕組み

AndroidカメラAPIのプレビューコールバックに渡されるビデオフレームのイメージをKXABarcodeReaderのデコードメソッド decode() に与えることにより、画像に含まれるバーコードの値を文字列データとして得ることができます。

KXABarcodeReader Android版でのバーコードの検出は、ビデオフレームの中央付近を通る水平線(スキャンライン)を基準に行われます。一度に複数のバーコードをデコードすることはできません。

KXABarcodeReaderはグローバルでスタティックな状態を持つので、複数のスレッドから非同期にAPIを呼び出すことはできません(同時並行デコード処理は不可能)。

Javaパッケージ

KXABarcodeReaderのJavaパッケージ名は「com.ukixa.barcode」です。 com.ukixa.barcodeパッケージは次の2つのクラスを含みます。

  1. BarcodeType
  2. BarcodeReader

次のようにバーコードリーダを利用するJavaソースファイルにインポートしてください。

import com.ukixa.barcode.BarcodeType;
import com.ukixa.barcode.BarcodeReader;

BarcodeTypeクラスにはKXABarcodeReaderがサポートするバーコードの種類を表す定数が宣言されています。 BarcodeReaderクラスはデコード機能を提供します。

BarcodeTypeクラス

KXABarcodeReaderがサポートするバーコードの種類は次の8種類に分けられます。

  1. BarcodeType.NW7 = NW-7 (CODABAR)
  2. BarcodeType.ITF = Interleaved 2 of 5
  3. BarcodeType.CODE39 = CODE39
  4. BarcodeType.CODE128 = CODE128 (GS1-128)
  5. BarcodeType.EAN13 = EAN-13/JAN-13, UPC-A
  6. BarcodeType.EAN8 = EAN-8/JAN-8
  7. BarcodeType.UPCE = UPC-E
  8. BarcodeType.GS1DATABAR = GS1 DataBar

BarcodeReaderクラス

BarcodeReaderクラスには次のようなメソッドがあります。

getInstance()

getInstance()メソッドは、BarcodeReaderクラスの共有インスタンスを返します。KXABarcodeReaderはグローバルでスタティックな状態を持つため、アプリ内で利用できるBarcodeReaderオブジェクトは1つだけです。あらかじめ生成された単一のインスタンスをアプリ全体で共有します。 new により新しいBarcodeReaderオブジェクトを生成することはできません。 getInstance()メソッドが返すオブジェクトを使ってください。

public static BarcodeReader getInstance();

getVersion()

getVersion()メソッドは、KXABarcodeReaderのバージョンと著作権を表す文字列を返します。

public static String getVersion();

getVersionNumber()

getVersionNumber()メソッドは、KXABarcodeReaderのバージョンを表す8桁の数値 (Binary Coded Decimal) を返します。

public static int getVersionNumber();

getLicense()

getLicense()メソッドは、ライブラリの使用許諾番号を表す文字列を返します。 ライセンスを購入していない(アプリがライセンスファイルを含まない)場合は、空の文字列を返します。

public String getLicense();

reset()

reset()メソッドは、BarcodeReaderオブジェクトの内部状態を初期状態にリセットします。 セッタメソッドで変更されていた値はデフォルト値に戻ります。

public void reset();

setTypes()

setTypes()は、読み取り(デコード)の対象としたいバーコードの種類を設定するためのメソッドです。バーコードの種類には前述の定数を指定します。複数の種類をデコード対象としたい場合は、ビット単位OR演算を使用します。

public void setTypes(int types);

EAN-13(UPC-A), EAN-8, UPC-Eを読み取り対象とする例:

barcodeReader.setTypes(BarcodeType.EAN13
    | BarcodeType.EAN8
    | BarcodeType.UPCE);

デフォルト値は BarcodeType.UNKNOWN (読み取り対象なし)です。

getTypes()

getTypes()メソッドは、setTypes()で設定された値を返します。

public int getTypes();

setRotation()

setRotation()メソッドは、decode()メソッドへの入力イメージとなるビデオフレームが回転している場合、それを正位置に戻す補正を行うための回転角を設定します。

public void setRotation(int angle);

decode()メソッドはsetRotation()メソッドで指定された角度だけ入力イメージを回転させてから解析処理を行います。 setRotation()の引数として整数値nを渡すと入力イメージを n × 90° 回転させます。 通常0、1、2、3いずれかの整数値を与えます。

デフォルト値はゼロ (0) です。

getRotation()

getRotation()メソッドは、setRotation()で設定された値を返します。

public int getRotation();

decode()

decode()は、引数として与えられたビデオフレームの輝度情報配列部分を解析、デコードするメソッドです。バーコードの検出に成功すれば、そのデータを文字列として返します。検出/デコードできなかった場合は空の文字列を返します。

※ライセンス未購入の試用状態では戻り値であるバーコード文字列の一部が伏せ字(アスタリスク「*」)になります。

オーバーロードされた2つのメソッドがあります。

public String decode(byte[] frame, int width, int height);
public String decode(ByteBuffer frame, int width, int height);

1つめのビデオフレームのデータをbyte配列として受け取るメソッドは、古いCamera APIからの利用を想定しています。 Camera APIのコールバック onPreviewFrame(byte[] data, Camera camera) メソッドからdecode()メソッドを呼び出します。width, heightにはコールバックメソッドの引数cameraから取得したフレームの幅と高さをそのまま渡します。

2つめのビデオフレームのデータをByteBufferとして受け取るメソッドは、Camera2 APIからの利用を想定しています。 ImageReaderのコールバック onImageAvailable(ImageReader reader) メソッドからdecode()メソッドを呼び出します。ByteBufferはImageReaderの保持しているイメージから取り出せます。width, heighにはImageReaderのgetWidth()、getHeight()メソッドで得られる値をそのまま渡します。

※ decode()メソッドに引き渡すByteBufferはダイレクトバッファでなければなりません

getType()

getType()メソッドは、直前のdecode()メソッド呼び出しでバーコードの検出に成功している場合、読み取ったバーコードの種類(BarcodeTypeクラスで宣言されている定数のいずれか)を返します。 バーコードが検出されていない場合、返値は不定です。

public int getType();

getText()

getText()メソッドは、直前のdecode()メソッド呼び出しでバーコードの検出に成功している場合、読み取ったバーコードデータ(文字列)を返します。バーコードが検出されていない場合、返値は不定です。

public String getText();

Kotlinからの利用

KotlinはJavaとの相互運用が可能ですので、KXABarcodeReader LibraryはKotlinベースのプロジェクトにも利用できます。Kotlin公式ドキュメント「Calling Java from Kotlin」に書かれているようにKotlinからJavaのコードを呼び出せます。

Javaクラスのアクセサメソッドは、Kotlinではプロパティとして扱われます。 BarcodeReaderクラスの場合、次のように読み替えてください。

Javaメソッド Kotlinプロパティ
setTypes/getTypes types
setRotation/getRotation rotation
getType type
getText text

API呼び出し手順

アプリに組み込む際の処理手順、APIをどのような順番で呼び出せばよいかを説明します。

アプリ(アクティビティ)が起動するタイミングで、バーコードリーダオブジェクト(BarcodeReaderの共有インスタンス)を取得します。

import com.ukixa.barcode.BarcodeType;
import com.ukixa.barcode.BarcodeReader;

public class MyActivity extends Activity {
    private BarcodeReader barcodeReader =
                       BarcodeReader.getInstance();
…

バーコード読み取り用のビューを表示し、カメラAPIのプレビュー動作を開始する手前のタイミングで、バーコードリーダオブジェクトの内部状態をリセットし、読み取りに必要なパラメータを設定します。

barcodeReader.reset();
barcodeReader.setRotation(3);
barcodeReader.setTypes(BarcodeType.GS1DATABAR);

カメラAPIのプレビューコールバックメソッドから得られるビデオフレームのデータを使ってデコード処理を行います。

古いCamera APIの例:

public void onPreviewFrame(byte[] data, Camera camera) {
    Camera.Parameters parameters = camera.getParameters();
    Size size = parameters.getPreviewSize();

    String barcode = barcodeReader.decode(data,
                                   size.width,
                                   size.height);
    if (!barcode.isEmpty()) {
        // 文字列が空でなければバーコードの検出に成功している。
        Log.d("MYTAG", "Type: " + barcodeReader.getType());
    }
}

Camera2 APIの例:

public void onImageAvailable(ImageReader imageReader) {
    if (imageReader != null) {
        Image image = imageReader.acquireLatestImage();
        if (image != null) {
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            // buffer.isDirect() == true であること。
            String barcode = barcodeReader.decode(buffer,
                              imageReader.getWidth(),
                              imageReader.getHeight());
            if (!barcode.isEmpty()) {
                // 文字列が空でなければバーコードの検出に成功している。
                Log.d("MYTAG", "Type: " + barcodeReader.getType());
            }
        }
    }
}

CameraX APIの例(Kotlinによる画像解析ユースケース):

override fun analyze(imageProxy: ImageProxy) {
    val buffer = imageProxy.planes[0].buffer
    val barcodeReader = BarcodeReader.getInstance()
    val text = barcodeReader.decode(buffer, imageProxy.width, imageProxy.height)
    if (text.isNotEmpty()) {
        // 文字列が空でなければバーコードの検出に成功している。
        Log.d("MYTAG", "type: ${barcodeReader.type}")
    }

    imageProxy.close()
}

初回のコールバック(1度のデコード処理)で正常にバーコードを読み取れるとは限りません。正常に読み取りが完了するまで、コールバックを連続して受け付けるようにします。バーコードの検出に成功したらコールバックを停止して構いません。

再び読み取りを行うには、バーコードリーダオブジェクトの内部状態をリセットするところから始めます。

ビデオフレームの設定

Android版KXABarcodeReaderでは、入力イメージのデータがYUV形式であることを前提にしています。プレビューイメージのフォーマットを、古いCamera APIでは「NV21」に、Camera2 APIでは「YUV_420_888」に設定してください。 入力イメージのフレームサイズ(画素数)は 1920 × 1080 ピクセル以下に設定してください。

適切な画素数は用途によって異なります。 EAN-13(UPC-A), EAN-8, UPC-E は 640 × 480 ピクセル程度でも読み取り可能です。 非常に長い可変長バーコード(CODE128に多い)や、サイズが小さいGS1 DataBarの場合、解像度を上げないと読み取れません。

適用業務と、実際に使用するAndroid端末のカメラの特性に応じて最適な画素数を割り出してください(むやみに画素数を上げても処理が重くなるだけで良い結果はえられません)。

お問い合わせ先

KXABarcodeReader Libraryについてのお問い合わせは、次の連絡先にお願いいたします。