概要
このガイドでは、ワークフロー入力を使用してデータを取得するアプリを開発する方法を説明します。この例では、身分証明書のスキャンに焦点を当てています。同様の手順は、他の OCR 機能 (ナンバー プレート、車両識別番号 (VIN)、タイヤ識別番号 (TIN)、メーター読み取り)、およびフリーフォーム イメージ キャプチャとドキュメント キャプチャに適用されます。
使用されたサンプルの身分証明書
![]() |
![]() |
|
米国 (ペンシルバニア州) およびノルウェーの運転免許証の例 |
身分証明書からデータを取得するアプリの開発方法について、詳細な手順を示すビデオ
ソース コードのファイルをダウンロードします。
要件
- DataWedge バージョン 11.2 以降 (バージョンを検索)
- スキャン フレームワーク 32.0.3.6 以降 (バージョンを検索)
- SD660 プラットフォーム上の Zebra モバイル コンピュータ
- Android 11 以降
- モバイル コンピュータの内蔵カメラ
- Mobility DNA OCR Wedge ライセンス - 次の各 OCR 機能に必要です
- Mobility DNA ナンバープレート OCR Wedge ライセンス
- Mobility DNA 身分証明書 OCR Wedge ライセンス
- Mobility DNA 車両識別番号 OCR Wedge ライセンス
- Mobility DNA タイヤ識別番号 OCR Wedge ライセンス
- Mobility DNA 検針 OCR Wedge ライセンス
パッケージの表示
重要: Android 11 (API 30) によろパッケージの表示が制限されているため、Android 11 以降を対象とする DataWedge アプリは、AndroidManifest.xml ファイルに次の <queries>
要素を含める必要があります。
<queries>
<package android:name="com.symbol.datawedge" />
</queries>
データを取得する手順
要約すると、ワークフロー入力を使用してデータを取得する手順は次のとおりです。
- DataWedge プロファイルを作成し、アプリケーションに関連付けます。
- スキャン結果を受信するようにアプリケーションを構成します。
- インテントから文字列データを抽出します。
- インテントから画像データを抽出します。
これらの手順の詳細について、次のサブセクションで説明します。
1.DataWedge プロファイルを作成し、アプリケーションに関連付けます
DataWedge でプロファイルを作成し、そのプロファイルをアプリに関連付けて、次のように設定します。
A. [ワークフロー入力] を有効にします。
B. [OCR] で、目的の OCR 機能を有効にします。ナンバー プレート、身分証明書、車両識別番号 (VIN)、タイヤ識別番号 (TIN)、メーター読み取りの中から選択できます。この場合は、[身分証明書] を有効にします。
[ワークフロー入力] および [身分証明書] を有効にします
C. キーストローク データを使用しない場合は、[キーストローク出力] を無効にします。
キーストローク出力を無効にします
D. [インテント出力] を有効にして、次の操作を実行します。
手順 1 からアプリでブロードキャスト レシーバを登録するために使用するインテント アクションとインテント カテゴリを指定します。この例では次のように指定します。
• インテント アクション: com.zebra.id_scanning.ACTION
• インテント カテゴリ: Intent.CATEGORY_DEFAULT[インテント配信] のメカニズムを選択します。この例では、[ブロードキャスト インテント] を選択します。
インテント出力の構成
2.スキャン結果を受信するようにアプリケーションを設定します
Android アプリケーション (例: IDScanningApp) を作成します。ブロードキャスト レシーバを登録して、ブロードキャスト インテントからスキャン結果を受信します。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.zebra.id_scanning.ACTION");
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(broadcastReceiver, intentFilter);
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
}
};
3.インテントから文字列データを抽出します
インテントから文字列データを抽出するために、スキャン結果のインテントには、com.symbol.datawedge.data
という文字列エクストラ (データ形式は JSON アレイ形式) が含まれます。身分証明書のデータ例を示します。
[
{
"group_id":"Uncategorized",
"imageformat":"YUV",
"orientation":"90",
"height":"1080",
"stride":"1920",
"size":"4147198",
"label":"ID card",
"width":"1920",
"uri":"content:\/\/com.symbol.datawedge.decode\/18-2-1",
"data_size":4147198
},
{
"group_id":"Result",
"string_data":"90",
"label":"weight",
"uri":"content:\/\/com.symbol.datawedge.decode\/18-2-2",
"data_size":2
},
{
"group_id":"Result",
"string_data":"M",
"label":"sex",
"uri":"content:\/\/com.symbol.datawedge.decode\/18-2-3",
"data_size":1
},
{
"group_id":"Result",
"string_data":"C91993805",
"label":"documentNumber",
"uri":"content:\/\/com.symbol.datawedge.decode\/18-2-5",
"data_size":9
},
{
"group_id":"Result",
"string_data":"ADAMS",
"label":"lastName",
"uri":"content:\/\/com.symbol.datawedge.decode\/18-2-6",
"data_size":5
}
]
ブロードキャスト レシーバで、com.symbol.datawedge.data
フィールドのデータを解析して JSONArray オブジェクトにします。JSONArray の各要素は JSONObject です。
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String jsonData = bundle.getString("com.symbol.datawedge.data");
try {
JSONArray jsonArray = new JSONArray(jsonData);
}
catch (Exception ex)
{
//Check error
}
}
};
JSONArray オブジェクトの要素を反復処理して、各フィールドのデータを抽出します。
- JSONObject に "string_data" という名前のマッピングがある場合は、この JSONObject に文字列データが含まれていることを意味します。"label" という名前でマッピングされた値を使用して、OCR 機能に基づいて文字列データの型を識別します。結果データの抽出でサポートされているフィールド名については、「OCR 結果出力」を参照してください。
- JSONObject に "string_data" という名前のマッピングがある場合は、この JSONObject に画像データが含まれていることを意味します。次の手順に進み、画像データを抽出します。
4.インテントから画像データを抽出します
DataWedge コンテンツ プロバイダにアクセスするために、アプリケーション マニフェスト ファイルに次の権限が追加されていることを確認します。
<uses-permission android:name="com.symbol.datawedge.permission.contentprovider" />
[URI] フィールドの値を使用して、DataWedge コンテンツ プロバイダにアクセスする URI を取得します。次に、ContentResolver を使用して URI を渡し、Cursor オブジェクトを取得します。Cursor オブジェクトには、次の 2 つの列があります。
名前 | 説明 |
---|---|
raw_data | 画像データを byte[] 形式で格納します |
next_data_uri | 残りの画像データの取得に使用する URI。残りの画像データがない場合、このフィールドは空になります。 |
raw_data
を読み取りそれを ByteArrayOutputStream
オブジェクトに保存します。next_data_uri
が空でない場合は、next_data_uri
列に指定されている URI から raw_data
を読み取ります。next_data_uri
が空になるまで、引き続き raw_data
フィールドを読み取って値を ByteArrayOutputStream オブジェクトに格納します。これは、次のように while ループを使用して実行できます。
String uri = jsonObject.getString("uri");
Cursor cursor = getContentResolver().query(Uri.parse(uri),null,null,null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if(cursor != null)
{
cursor.moveToFirst();
baos.write(cursor.getBlob(cursor.getColumnIndex("raw_data")));
String nextURI = cursor.getString(cursor.getColumnIndex("next_data_uri"));
while (nextURI != null && !nextURI.isEmpty())
{
Cursor cursorNextData = getContentResolver().query(Uri.parse(nextURI),
null,null,null);
if(cursorNextData != null)
{
cursorNextData.moveToFirst();
baos.write(cursorNextData.getBlob(cursorNextData.
getColumnIndex("raw_data")));
nextURI = cursorNextData.getString(cursorNextData.
getColumnIndex("next_data_uri"));
cursorNextData.close();
}
}
cursor.close();
}
すべての値が画像データ用に保存されている場合は、下の表に示す画像出力でサポートされているフィールド名 (例えば「width」、「height」など) によってマップされた値を読み取り、Bitmap オブジェクトを構築します。
画像出力
フィールド名 | タイプ | 説明 |
---|---|---|
label | string | サンプルの型を指定する画像ラベル名。「ナンバー プレート」、「身分証明書」、「VIN」、「TIN」、「メーター」 |
width | int | 画像の幅 (ピクセル単位) |
height | int | 画像の高さ (ピクセル単位) |
size | int | 画像バッファのサイズ (ピクセル単位) |
stride | int | 画像の 1 行の幅 (ピクセル単位) |
imageformat | string | サポートされている形式: Y8、YUV 注: YUV 形式は NV12 形式として解釈する必要があります。 |
orientation | int | 画像バッファの回転角度 (度単位)。値: 0、90、180、270 |
ImageProcessing
クラスの getBitmap()
メソッド (下に示す) を使用して、Bitmap オブジェクトを取得します。
int width = 0;
int height = 0;
int stride = 0;
int orientation = 0;
String imageFormat = "";
width = jsonObject.getInt("width");
height = jsonObject.getInt("height");
stride = jsonObject.getInt("stride");
orientation = jsonObject.getInt("orientation");
imageFormat = jsonObject.getString("imageformat");
Bitmap bitmap = ImageProcessing.getInstance().getBitmap(baos.toByteArray(),imageFormat, orientation,stride,width, height);
Class ImageProcessing
:
/*
* Copyright (C) 2018-2021 Zebra Technologies Corp
* All rights reserved.
*/
package com.zebra.idscanningapp;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import java.io.ByteArrayOutputStream;
public class ImageProcessing{
private final String IMG_FORMAT_YUV = "YUV";
private final String IMG_FORMAT_Y8 = "Y8";
private static ImageProcessing instance = null;
public static ImageProcessing getInstance() {
if (instance == null) {
instance = new ImageProcessing();
}
return instance;
}
private ImageProcessing() {
//Private Constructor
}
public Bitmap getBitmap(byte[] data, String imageFormat, int orientation, int stride, int width, int height)
{
if(imageFormat.equalsIgnoreCase(IMG_FORMAT_YUV))
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
int uvStride = ((stride + 1)/2)*2; // calculate UV channel stride to support odd strides
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, new int[]{stride, uvStride});
yuvImage.compressToJpeg(new Rect(0, 0, stride, height), 100, out);
yuvImage.getYuvData();
byte[] imageBytes = out.toByteArray();
if(orientation != 0)
{
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
return Bitmap.createBitmap(bitmap, 0 , 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
else
{
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
}
}
else if(imageFormat.equalsIgnoreCase(IMG_FORMAT_Y8))
{
return convertYtoJPG_CPU(data, orientation, stride, height);
}
return null;
}
private Bitmap convertYtoJPG_CPU(byte[] data, int orientation, int stride, int height)
{
int mLength = data.length;
int [] pixels = new int[mLength];
for(int i = 0; i < mLength; i++)
{
int p = data[i] & 0xFF;
pixels[i] = 0xff000000 | p << 16 | p << 8 | p;
}
if(orientation != 0)
{
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
Bitmap bitmap = Bitmap.createBitmap(pixels, stride, height, Bitmap.Config.ARGB_8888);
return Bitmap.createBitmap(bitmap, 0 , 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
else
{
return Bitmap.createBitmap(pixels, stride, height, Bitmap.Config.ARGB_8888);
}
}
}
OCR 結果出力
スキャン結果のインテントには、com.symbol.datawedge.data
という文字列エクストラが含まれていて、そこからデータを抽出できます。このセクションでは、各 OCR 機能で使用可能なフィールド名と、身分証明書の場合に使用できる追加のフィールド名について説明します。使用方法については、「インテントから文字列データを抽出する」を参照してください。
OCR 結果
フィールド名 | 説明 |
---|---|
string_data | OCR ベースの機能から読み取られたテキスト データ。ナンバー プレート、車両識別番号、タイヤ識別番号、またはメーター。例外は 身分証明書で、多数のフィールド名を返すことができます。以下のセクションを参照してください。 |
data_size | データの長さ |
身分証明書
以下の表は、運転免許証、ID カードや健康保険証から読み取ることができるデータ フィールドを示しています。一部のフィールド名は、地域に基づいた文書では異なることがあります。
返されるデータは、身分証明書の内容によって異なります。フィールド名が (以下の表で) 必須に指定されている場合は、一部の身分証明書に存在しない可能性があります。このような場合、フィールド名を照会してもデータは返されません。例:
- メキシコの投票者 ID (タイプ C) - 生年月日と文書番号が存在しません
- メキシコの投票者 ID (タイプ G) - 文書番号が存在しません
- オーストラリアの運転免許証 (NSW) - 名と姓が独立したフィールドとして存在せず、[名前] という単一のフィールドに結合されています。
凡例:
- O- オプション
- M- 必須
番号 | フィールド名 | 運転免許証 | ID カード | 健康保険証 |
---|---|---|---|---|
1 | additionalInformation | N/A | O | N/A |
2 | additionalInformation1 | N/A | O | N/A |
3 | address | M | N/A | N/A |
4 | age | N/A | O | N/A |
5 | audit | O | N/A | N/A |
6 | authority | O | O | M |
7 | cardAccessNumber | N/A | O | N/A |
8 | cardNumber | O | N/A | N/A |
9 | categories | O | N/A | N/A |
10 | citizenship | N/A | O | N/A |
11 | cityNumber | N/A | O | N/A |
12 | class | O | N/A | N/A |
13 | conditions | O | N/A | N/A |
14 | country | O | O | N/A |
15 | dateOfBirth | M | M | M |
16 | dateOfExpiry | O | O | M |
17 | dateOfIssue | M | O | N/A |
18 | dateOfRegistration | N/A | O | N/A |
19 | divisionNumber | N/A | O | N/A |
20 | documentDiscriminator | O | N/A | N/A |
21 | documentNumber | M | M | M |
22 | duplicate | O | N/A | N/A |
23 | endorsements | O | N/A | N/A |
24 | eyes | O | N/A | N/A |
25 | familyName | N/A | O | N/A |
26 | fathersName | N/A | O | N/A |
27 | firstIssued | O | N/A | N/A |
28 | firstName | M | M | M |
29 | folio | N/A | O | N/A |
30 | fullName | N/A | O | N/A |
31 | hair | O | N/A | N/A |
32 | 高さ | O | O | N/A |
33 | lastName | M | M | M |
34 | licenseClass | N/A | O | N/A |
35 | licenseType | N/A | O | N/A |
36 | municipalityNumber | N/A | O | N/A |
37 | name | M | N/A | N/A |
38 | nationalId | N/A | O | N/A |
39 | nationality | N/A | O | M |
40 | office | O | N/A | N/A |
41 | parentsGivenName | N/A | O | N/A |
42 | parish | O | N/A | N/A |
43 | personalNumber | O | O | M |
44 | placeAndDateOfBirth | N/A | O | N/A |
45 | placeOfBirth | O | O | N/A |
46 | previousType | O | N/A | N/A |
47 | restrictions | O | N/A | N/A |
48 | revoked | O | N/A | N/A |
49 | sex | O | O | N/A |
50 | stateNumber | N/A | O | N/A |
51 | supportNumber | N/A | O | N/A |
52 | type | O | N/A | N/A |
53 | version | O | N/A | N/A |
54 | verticalNumber | O | N/A | N/A |
55 | voterId | N/A | O | N/A |
56 | weight | O | N/A | N/A |
関連ガイド: