画像からテキストをコピーする方法&GASでOCR

画像からテキストをコピーする方法&GASでOCR

「OCR」とは印刷された文字や手書き文字を、デジタル画像にして、コンピュータが利用できるデジタルの文字コードに変換する技術です

この画像は、パソコン画面のスクリーンショットです
「OCR」を利用すればテキストをコピーできるようになります

余談 ちなみに、macOS Montereyは「画像内のテキスト認識機能」をオンにできるようです

目次
  1. Googleドキュメントを利用する
  2. Cloud Vision APIの「試してみましょう」を利用
  3. GASでOCR用サイトを自作
    1. コード
    2. GAS備忘録

Googleドキュメントを利用する

*Googleアカウントが必要です

Googleドライブから画像やPDFを 「Googleドキュメントで開く」だけでテキストが表示されます

GoogleドキュメントでOCR
  1. パソコンでGoogleドライブを開きます

  2. ファイルをアップロードします

  3. ファイルを「右クリック」して「アプリで開く」から「Googleドキュメント」をクリックします

  4. ドライブには「アップロードした画像ファイル」と「Googleドキュメントのファイル」が保存されています

ファイルを準備する
次のヒントを参考にするとファイルを最適な状態で準備できます。
形式: .JPEG、.PNG、GIF、PDF(複数ページのドキュメント)の各ファイル。
ファイルサイズ: ファイルは 2 MB 以下にします。
解像度: テキストの高さは 10 ピクセル以上にします。
向き: ドキュメントは正しい向きにします。画像の向きが間違っている場合は、回転させてから Google ドライブにアップロードします。
言語: Google ドライブではドキュメントの言語は検出されません。
フォントと文字セット: 最適な結果を得るには、Arial や Times New Roman のような一般的なフォントを使用します。
画質: 明るさが均一でコントラストがはっきりしたシャープな画像が最適です

Googleドライブヘルプより
https://support.google.com/drive/answer/176692?hl=ja&co=GENIE.Platform%3DDesktop

保存された「ファイルの削除」が面倒だったりします😅

Cloud Vision APIの「試してみましょう」を利用

「Google Cloud Vision API」は「Vision AI(クラウド上で画像を分析するAI)」を使用して、画像分析情報を取得できるサービスです
「Cloud Vision APIのガイド」にある「試してみよう」を利用させていただきます

画像をアップロードして、reCAPTCHAの確認(ロボットではありませんにチェック)をするだけです

「Text」のタブを選択すると右側にテキストが表示されます

ファイルを削除する手間はかからないのですが、反対に保存できません
そして、残念なことに不要な半角スペースが入ります😂

GASでOCR用サイトを自作

個人的に「画像」をメモ代わりに保存するのですが、画像の文字だけをテキストとして残したく、GASで自分専用OCRサイトを自作しました^^;

画像をGoogleドライブにアップロードして(複数枚可能)
「テキストだけを画面に表示」したり「アップロードした画像を表示」したり、不要になれば「一括で削除」したりできます

コード

GoogleドライブにOCR用フォルダを新規作成して、IDを控えます

//作成したフォルダのURL
https://drive.google.com/drive/folders/{この部分がフォルダID}

GASファイルを作成します「新規→その他→Google Apps Script」
左側「サービス」から「Drive API」を追加します
*コードにフォルダIDを追加

function doGet(request) {
  return HtmlService.createTemplateFromFile('index')
      .evaluate();
}
//作成したフォルダのID
const folderId = 'フォルダID';
//画像アップロード
function uploadImg(formObject){
  let folder = DriveApp.getFolderById(folderId); 
  let formBlob = formObject.myFile;
  folder.createFile(formBlob);
  return 'アップロード完了'  
}
//テキストだけを返す
function ocrText() {
  const files = DriveApp.getFolderById(folderId).getFiles();
// テキストを格納する変数
  let result = '';
// 画像ファイルをループ処理
  while(files.hasNext()){
    let file = files.next();
    //ocrを有効に
    let image = Drive.Files.copy({ title: file.getName() }, file.getId(), {'ocr': true});
    //ドキュメントで開く
    let doc = DocumentApp.openById(image.id);
    let text = doc.getBody().getText();
    //ドキュメント削除
    Drive.Files.remove(doc.getId());
   result = result + `${text}---ここまで---` //複数枚用の目印
  }
  return result;
}
//フォルダ内のファイル全部削除する
function deletFiles(){
  const files = DriveApp.getFolderById(folderId).getFiles()
   while (files.hasNext())  {
   let file = files.next();
   file.setTrashed(true) //ごみ箱へ
  }
  return '削除完了'
}
//画像ファイルのidからURLを取得する
function getImgIds(){
  const files = DriveApp.getFolderById(folderId).getFiles()
  const imgId = []
  while (files.hasNext()){
    var file = files.next();
    file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
    imgId.push(`https://drive.google.com/uc?id=${file.getId()}`)
  }
  return imgId;
}

左側「ファイル→HTML→indexと入力」でindex.htmlファイルを追加します
*CDNで読み込んだ「Bootstrap」を使って、ある程度見た目を整えました

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  </head>
<body>
  <div class="container my-4">
   <section class="p-3 border">
    <form onsubmit="handleSubmit(this)" class="row g-2">
      <div class="col-auto">
       <label for="myFile" class="form-label">画像アップロード</label>
       <input id="myFile" class="form-control" name="myFile" type="file" required />
      </div>
      <div class="col-12">
       <input class="btn btn-secondary mb-3" type="submit" value="アップロード" />
      </div> 
      <div id="output"></div>
    </form>
   </section> 
   <section class="mt-3 p-3 border">
      <button id="textBtn" class="btn btn-secondary mb-3">テキストファイルを表示する</button>
      <div id="showText"></div>
   </section>
   <section class="mt-3 p-3 border">
      <button id="imgBtn" class="btn btn-secondary mb-3">画像を表示する</button>
      <div id="showImg"></div>
   </section>
   <section class="mt-3 p-3 border">
     <button id="deleteBtn" class="btn btn-danger mb-3">フォルダ内のファイル全て削除</button>
      <div id="showStats"></div>
   </section>
  </div>
<script>
  //フォーム送信を止めます
   function preventFormSubmit() {
     var forms = document.querySelectorAll('form');
      for (var i = 0; i < forms.length; i++) {
        forms[i].addEventListener('submit', function(event) {
        event.preventDefault();
         });
        }
   }
   window.addEventListener('load', preventFormSubmit);
    
  //画像アップロード
  function handleSubmit(formObject) {  
    const output = document.querySelector('#output');
    output.innerHTML = '<p>loading・・・</p>'
    google.script.run.withSuccessHandler((arg)=> {
      output.innerHTML = `<p>${arg}</p>`; 
     }).uploadImg(formObject);
  }    
 //画面処理
  function views(btn, el, func){
    const btnEl = document.querySelector(btn)
    btnEl.addEventListener('click', ()=>{
     const output = document.querySelector(el);
     output.innerHTML = '<p>処理中・・・</p>'
     func(output)
    })
  }
 //テキストの取得
  function gText(output){
     google.script.run.withSuccessHandler((arg)=>{
     output.innerHTML = `<div><pre class="text-wrap">${arg}</pre></div>`
    }).ocrText();
  }
  views('#textBtn', '#showText', gText)
 //OCRフォルダのファイルを全て削除
  function gDeletFile(output){
    google.script.run.withSuccessHandler((arg)=>{
    output.innerHTML = `<p>${arg}</p>`
    }).deletFiles();
  }
  views('#deleteBtn', '#showStats', gDeletFile)
 //画像を表示
  function gShowImg(output){
    google.script.run.withSuccessHandler((urls)=>{
    let li = urls.reduce((accu, str) => {
     return accu + `<li class="list-group-item col-12 col-md-6"><img src="${str}" class="img-fluid" /></li>`
     }, '')
    output.innerHTML = `<ul class="list-group flex-row flex-wrap">${li}</ul>`
    }).getImgIds()
  }
  views('#imgBtn', '#showImg', gShowImg)
</script>
</body>
</html>

「デプロイ→新しいデブロイ→歯車のアイコン→ウェブアプリ」からアクセスできるユーザー(公開範囲)を選択して、公開します
*アクセス権限の承認は
権限を確認→アカウントを選択して→詳細→プロジェクトに移動→許可をクリック


ChromeブラウザのデスクトップにOCRサイトのショートカット作成

GAS備忘録

「GAS」で「OCR」利用するには、GASで通常使う「Drive Service」ではなく「Drive API(Driveサービス)」を使う必要があります
サービスから「Driveサービス」を追加します

「Drive API(Driveサービス)」の「Driveメソッド」はGASのの組み込みサービスとほぼ同じように使えます

ドライブ内の画像をWebページで表示するには
画像ファイル(または保存しているフォルダ)を「リンクを知っている全員が閲覧可」にする必要があります

setSharing(accessType, permissionType)
setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
//imgタグのsrcに設定するurl
https://drive.google.com/uc?id={ファイルID}
,