Extracting text from an image: Experiments with Shape Detection

Google IOの後に少しダウンタイムがあり、長期にわたるかゆみを掻きたいと思いました。ブラウザの画像内に保持されているテキストをコピーしたいだけです。以上です。誰にとっても素晴らしい機能になると思います。

Chromeに機能を直接追加するのは簡単ではありませんが、Androidのインテントシステムを利用できることはわかっています。Web(または少なくともAndroidのChrome)でそれを実行できるようになりました。

二つの新しいWebプラットフォームへの追加-共有ターゲットレベル2(または私はそれが共有ファイルを呼び出すために好きなように)とTextDetector形状検出APIで- have allowed me to build a utility that I can Share images to and get the text held inside them

基本的な実装は比較的単純で、Service Workerで共有ターゲットとハンドラーを作成し、ユーザーが共有したイメージをTextDetectorしたら、 TextDetectorを実行します。

Share Target API使用すると、Webアプリケーションをネイティブ共有サブシステムの一部にすることができます。この場合、次のようにWeb App Manifest内で宣言することにより、すべてのimage/*タイプを処理するように登録できます。

"share_target": {
  "action": "/index.html",
  "method": "POST",
  "enctype": "multipart/form-data",
  "params": {
    "files": [
      {
        "name": "file",
        "accept": ["image/*"]
      }
    ]
  }
}

PWAをインストールすると、次のように、画像を共有するすべての場所でPWAが表示されます。

Share Target APIは、共有ファイルをフォームポストのように扱います。ファイルがWebアプリと共有されると、サービスワーカーがアクティブになり、ファイルデータを使用してfetchハンドラーが呼び出されます。現在、データはService Worker内にありますが、現在のウィンドウで必要になります。処理できるように、サービスはどのウィンドウがリクエストを呼び出したかを知っているので、クライアントを簡単にターゲットにしてデータを送信できます。

self.addEventListener('fetch', event => {
  if (event.request.method === 'POST') {
    event.respondWith(Response.redirect('/index.html'));
    event.waitUntil(async function () {
      const data = await event.request.formData();
      const client = await self.clients.get(event.resultingClientId || event.clientId);
      const file = data.get('file');
      client.postMessage({ file, action: 'load-image' });
    }());
    
    return;
  }
  ...
  ...
}

画像がユーザーインターフェイスに表示されたら、テキスト検出APIで処理します。

navigator.serviceWorker.onmessage = (event) => {  
  const file = event.data.file;
  const imgEl = document.getElementById('img');
  const outputEl = document.getElementById('output');
  const objUrl = URL.createObjectURL(file);
  imgEl.src = objUrl;
  imgEl.onload = () => {
    const texts = await textDetector.detect(imgEl);
    texts.forEach(text => {
      const textEl = document.createElement('p');
      textEl.textContent = text.rawValue;
      outputEl.appendChild(textEl);
    });
  };
  ...
};

最大の問題は、ブラウザが画像を自然に回転させないことです(以下を参照)。ShapeDetection APIでは、テキストを正しい読み方向にする必要があります。

かなり使いやすいEXIF-Js libraryを使用して回転を検出し、基本的なキャンバス操作を行って画像の向きを変更しました。

EXIF.getData(imgEl, async function() {
  // http://sylvana.net/jpegcrop/exif_orientation.html
  const orientation = EXIF.getTag(this, 'Orientation');
  const [width, height] = (orientation > 4) 
                  ? [ imgEl.naturalWidth, imgEl.naturalHeight ]
                  : [ imgEl.naturalHeight, imgEl.naturalWidth ];

  canvas.width = width;
  canvas.height = height;
  const context = canvas.getContext('2d');
  // We have to get the correct orientation for the image
  // See also https://stackoverflow.com/questions/20600800/js-client-side-exif-orientation-rotate-and-mirror-jpeg-images
  switch(orientation) {
    case 2: context.transform(-1, 0, 0, 1, width, 0); break;
    case 3: context.transform(-1, 0, 0, -1, width, height); break;
    case 4: context.transform(1, 0, 0, -1, 0, height); break;
    case 5: context.transform(0, 1, 1, 0, 0, 0); break;
    case 6: context.transform(0, 1, -1, 0, height, 0); break;
    case 7: context.transform(0, -1, -1, 0, height, width); break;
    case 8: context.transform(0, -1, 1, 0, 0, width); break;
  }
  context.drawImage(imgEl, 0, 0);
}

そして出来事、あなたがアプリに画像を共有する場合、それは画像を回転させてから、それを見つけて見つけたテキストの出力を返します。

この小さな実験を作成するのは信じられないほど楽しかったです、そして、それは私にとってすぐに役に立ちました。ただし、 inconsistency of the web platform強調表示しinconsistency of the web platform 。これらのAPIはすべてのブラウザで利用できるわけではなく、Chromeのすべてのバージョンで利用できるわけでもありません-つまり、この記事を書いているChrome OSではアプリを使用できませんが、同時に使用できるのです... OMG、とてもクール。

About Me: Paul Kinlan

I lead the Chrome Developer Relations team at Google.

We want people to have the best experience possible on the web without having to install a native app or produce content in a walled garden.

Our team tries to make it easier for developers to build on the web by supporting every Chrome release, creating great content to support developers on web.dev, contributing to MDN, helping to improve browser compatibility, and some of the best developer tools like Lighthouse, Workbox, Squoosh to name just a few.