kivyLauncher + zxing でバーコードスキャン、事始

いつだって自分向け。

どっかでも書いたように、いまだに「オンラインショッピング」が出来なくて、現物を店で見て買いたい人である。なので、amazon とかで買うのは、中身がある程度わかっていて、どうしても書店やレコード店にないのでやむなく、って場合だけ。

そうするとさ…、「あれ? これ、持ってたっけ、持ってなかったっけ?」と、店で思い出せなくて困ることが結構多い。なので、「既に持ってるリスト」が欲しい。バーコードリーダは簡単に使えそうだしなぁ、と思った。

ただ… Google Play ストアから手に出来る出来合いのものはどうも自分のニーズには合わなそうだった。

ちょっと調べ始めてみたら、結構簡単に作れそうだったので、やってみたら確かに簡単だった、ってハナシ。

まぁだいたい一日でひとまずの正解に辿り着けたので、その流れだけざーっと書いとく:

  1. Google 公式な android API は visionの中

  2. 探ってたら、Android Barcode and Qr Scanner Exampleなんてチュートリアルが、かなりシンプルに書いているのを見つける。

    In this example, we are going to see how the Android Barcode and Qr Scanner is implemented via the use of the ZXing (Zebra Crossing) library, which will help us to carry out barcode scanning within an Android app.

    はーん、ZXing をインストールするとライブラリとしても使えるってことか…。核心部だけ抽出すると java でこう:

     1 import android.app.Activity;
     2 import android.content.Intent;
     3 import android.os.Bundle;
     4 import android.view.View;
     5 import android.widget.Toast;
     6 
     7 public class AndroidBarcodeQrExample extends Activity {
     8     /** Called when the activity is first created. */
     9 
    10     @Override
    11     public void onCreate(Bundle savedInstanceState) {
    12         super.onCreate(savedInstanceState);
    13         setContentView(R.layout.activity_main);
    14     }
    15 
    16     public void scanBar(View v) {
    17 	Intent intent = new Intent("com.google.zxing.client.android.SCAN");
    18 	intent.putExtra("SCAN_MODE",
    19 			"PRODUCT_MODE");  // PRODUCT_MODE or QR_CODE_MODE
    20 	startActivityForResult(intent, 0);
    21     }
    22 
    23     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    24         if (requestCode == 0) {
    25             if (resultCode == RESULT_OK) {
    26                 String contents = intent.getStringExtra("SCAN_RESULT");
    27                 String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
    28 
    29                 Toast toast = Toast.makeText(this, "Content:" + contents + " Format:" + format, Toast.LENGTH_LONG);
    30                 toast.show();
    31             }
    32         }
    33     }
    34 }
    

    これを kivy に読み替えるのならそう難しくなさそうだなぁ、と。

  3. ZXing の GitHubに行って見ると python-zxing なる Python binding があることを知るが…、いやぁ、これはないわ。まず subprocess を使って java を起動するってノリもヒドいが、それ以前の問題として、ソースを見ただけで「画像ありき」のスキャナ。カメラの起動からはやってない。
  4. てわけでさっきの AndroidBarcodeQrExample からやろうっと。
  5. Intent, startActivityForResult, Activity, onActivityResult の対応付けが不慣れでワガらんなぁ、と探ってたら、ほとんど同じことをしている人がいた。ラッキー。あーそうそう、まさに onActivityResult がわからんかったの。

てわけで、ひとまずは、起動するとイキナリ Zxing 起動し、ただログに結果を書き出すだけの「事始」:

 1 # -*- coding: utf-8 -*-
 2 # /sdcard/kivy/zxing_barcodedemo_0:
 3 #     main.py: このファイル。
 4 #     android.txt は以下のような具合。
 5 #         title=Barcode Scanner with Zxing - Demo 1
 6 #         author=hhsprings
 7 #         orientation=all
 8 from kivy.lang import Builder
 9 from kivy.app import App
10 from jnius import autoclass, cast
11 from android import activity
12 from kivy.logger import Logger
13 
14 kv = '''
15 BoxLayout:
16     orientation: 'vertical'
17 '''
18 
19 Intent = autoclass('android.content.Intent')
20 PythonActivity = autoclass('org.renpy.android.PythonActivity')
21 
22 class ZxingBarcode0App(App):
23 
24     def build(self):
25         #
26         activity.bind(on_activity_result=self.on_activity_result)
27 
28         #
29         intent = Intent("com.google.zxing.client.android.SCAN")
30         # SCAN_MODE: PRODUCT_MODE or QR_CODE_MODE
31         intent.putExtra("SCAN_MODE", "PRODUCT_MODE")
32         PythonActivity.mActivity.startActivityForResult(intent, 0)
33 
34         return Builder.load_string(kv)
35 
36     def on_activity_result(self, requestCode, resultCode, intent):
37         Logger.info("requestCode={}".format(resultCode))
38         if requestCode != 0:
39             return
40         contents = intent.getStringExtra("SCAN_RESULT")
41         format = intent.getStringExtra("SCAN_RESULT_FORMAT")
42         Logger.info("{}, {}".format(contents, format))
43 
44 
45 if __name__ == '__main__':
46     ZxingBarcode0App().run()

あらま、いちぱつで動きましたな。

ログについてはひとつ前の投稿参照。

こんなログ:

[INFO              ] 4988031166260, EAN_13

ふむ。あとは SQLite でデータ管理、で目的のものが作れるな。