Monacaを使って何かアプリを作ってみたいと思っても、いざとなるとアイデアが出てこないかもしれません。また、最初から大きなアプリを作ろうと思うと、何から手を付けて良いのか分からないことでしょう。

そこで、この記事では手順を踏んで簡単なアプリを開発してみます。最初の一歩として、ぜひチャレンジしてみてください。

今回はTesseract.jsとNCMB(ニフクラmobile backend)を使って、多言語対応のOCRアプリを開発します。撮影した写真からテキスト情報を抜き出し、それを履歴として保存できます。

利用している技術、ライブラリ

このアプリで利用している技術やライブラリは次の通りです。

OCRライブラリとしてTesseract.jsを使います。Tesseract.jsはJavaScriptだけで動作するOCRライブラリで、100以上の言語に対応しています。videoやcanvasタグも使えますが、実用性という意味では画像が良いでしょう。

また、今回はMonacaでFramework7のCore Tab View テンプレートを選択しています。Monaca IDEからはフレームワークテンプレート > JavaScript > Framework7 Core Tab Viewと選択します。

サンプルアプリの画面

このアプリの画面は次の通りです。

目的

OCRアプリではカメラを使って写真を撮影したり、既存の画像を選択します。

画像を指定すると、その画像に対してOCR処理が開始されます。

今回は英語と日本語を対象としています。

言語の選択は、ユーザ自身が切り替える仕様となっています。

また、OCR処理での解析結果は、クラウドDBである ニフクラ mobile backend に保存されます。

ログイン画面

このアプリではID、パスワードを用いた認証機能を提供します。

OCR画面

画像を選択して、OCR処理を行います。処理中はプログレスバーが表示され、完了すると解析されたテキストが表示されます。

履歴画面

これまでに解析した画像と、その結果が一覧表示されます。

詳細画面

一覧画面で選択したOCR結果について、その画像とテキストを表示します。

ユーザーデータの権限

データは自分だけが読み書き可能としています。写真を扱うので、他人に読まれる可能性があるのは良くないでしょう。

ニフクラ mobile backendのキーを取得

ニフクラ mobile backendにユーザー登録、またはログインしてアプリを作成します。その結果として、次の2つのキーが取得できます。

  • アプリケーションキー
  • クライアントキー

ライブラリのインストール

外部ライブラリとして、ncmbを追加します。JavaScriptライブラリですので、JS/CSSコンポーネントの追加と削除から行ってください。

読み込むファイルとしてncmb.min.jsをチェックするのを忘れないでください。

Tesseract.jsのインストール

Tesseract.jsは、CDNによる利用を採用します。

これは www/index.html に記述します。

<script src="https://unpkg.com/tesseract.js@v2.1.0/dist/tesseract.min.js"></script>

バックエンドサービス(NCMB)の初期化

www/js/app.js を開いて、下記のようにニフクラmobile backendを初期化する処理を追加します。

上記で紹介したアプリケーションキーとクライアントキーを適用してください。

const applicationKey = "YOUR_APPLICATION_KEY";
const clientKey = "YOUR_CLIENT_KEY";
const ncmb = new NCMB(applicationKey, clientKey);

ルーティング

どのURLへ擬似的にアクセスした際にどの画面を出すかは js/routes.js で定義しています。

const routes = [
  {
    path: "/",
    url: "./index.html",
  },
  // ログイン画面
  {
    path: "/login",
    name: "Login",
    componentUrl: "./pages/login.html"
  },
  // データ投入画面
  {
    path: "/camera",
    name: "Camera",
    componentUrl: "./pages/camera.html"
  },
  // データ一覧画面
  {
    path: "/list",
    name: "List",
    componentUrl: "./pages/list.html"
  },
  // データ詳細画面
  {
    path: "/:id",
    name: "Detail",
    componentUrl: "./pages/show.html"
  },
  // Default route (404 page). MUST BE THE LAST
  {
    path: "(.*)",
    url: "./pages/404.html",
  },
];

index.html の紹介

Monacaアプリで一番初めに読み込まれる www/index.html ではツールバーを用意します。OCRと履歴表示、2つのタブを配置します。

<div id="app">
  <!-- Views/Tabs container -->
  <div class="views tabs safe-areas">
    <div class="toolbar toolbar-bottom tabbar-labels">
      <div class="toolbar-inner">
        <a href="#view-home" class="tab-link tab-link-active">
          <i class="icon material-icons">camera</i>
          <span class="tabbar-label">OCR</span>
        </a>
        <a href="#view-list" class="tab-link">
          <i class="icon material-icons">list</i>
          <span class="tabbar-label">履歴</span>
        </a>
      </div>
    </div>

    <!-- Your main view/tab, should have "view-main" class. It also has "tab-active" class -->
    <div id="view-home" class="view view-main view-init tab tab-active" data-url="/camera">
    </div>
    <div id="view-list" class="view view-init tab" data-name="List" data-url="/list">
    </div>
  </div>
</div>

認証画面への遷移

pages/camera.html では画面表示時のイベントで認証の判定を行っています。

ログインしていない場合には、 pages/login.html に遷移させます。

ログインしていると判断された場合は、セッションが無効になっている可能性があるので、データストアに実際アクセスして判定を行っています。

詳細は、以下のコメントを参照してください。

// ページ初期化時に実行されるイベント
$on("pageBeforeIn", async (e, page) => {
  // 認証状態のチェック
  if (!(await checkAuth())) {
    // false が返ってきたらログイン画面に遷移
    $f7router.navigate({name: "Login"});
  }
});

// 認証状態をチェックする関数(js/app.js内に定義しています)
// 認証が問題なければ true / ログインしていない or セッションに問題がある場合は false
const checkAuth = async () => {
  // 現在のログインユーザを取得
  const user = ncmb.User.getCurrentUser();
  // データがない場合は false を返す
  if (!user) return false;

  try {
    // セッションの有効性チェック
    await ncmb.DataStore("Test").fetch();
    // 問題なければ true
    return true;
  } catch (e) {
    // セッションに問題がある場合は false
    return false;
  }
}

ユーザ登録/ログイン処理 (login.html)

ユーザ登録/ログイン処理は pages/login.html のボタンをタップした際に signInOrLogin にて行われます。

全体の流れは次のようになります。

// 新規登録 & ログインボタンをタップした際のイベント
const signInOrLogin = async () => {
  // 入力値をオブジェクト化(app.jsにて定義)
  const params = serializeForm("form#login");

  // ユーザ登録処理    
  try {
    await registerUser(params);
  } catch (e) {
    // すでに同じ名前で登録されている場合はエラー
    // 今回は無視して次に進みます
  }

  try {
    // ログインと権限設定の処理
    await loginUser(params);
    // 前の画面に戻る
    $f7router.back();
  } catch (e) {
    // ログイン失敗したらアラート
    console.log(e);
    $f7.dialog.alert("ログイン失敗しました。ID、パスワードを確認してください");
  }
}

NCMBへのユーザ登録を行う registerUser は次のような実装になります。

入力値をユーザオブジェクトにセットし、 signUpByAccount メソッドを実行します。

// ユーザ登録処理
const registerUser = (params) => {
  const user = new ncmb.User;
  return user
    .set("userName", params.userName)
    .set("password", params.password)
    .signUpByAccount();
}

ログイン処理は loginUser 関数にて行います。

この処理ではNCMBのログイン処理 ncmb.User.login を実行しているだけです。

const loginUser = async (params) => {
  // ログイン処理
  return ncmb.User.login(params.userName, params.password);
}

これでログイン処理が完成です。

まとめ

ここまでの流れでログイン判定と、ユーザ登録/ログイン処理が完成となります。Framework7はルーティングも分かりやすく、画面ごとに処理も分かれているのでアプリ開発しやすいかと思います。ぜひ試してみてください。

次回はOCRアプリの解析と、履歴表示を作成していきます。