LoginSignup
3
2

「文字練習bot」~canvasで文字を書き、OCRで読み取る~

Last updated at Posted at 2024-03-27

最近、以下の技術を習得しました(Qiita記事)
LIFFで描画(canvas)して、画像をLINEへ送信する。「お絵描きbot」
https://qiita.com/21HideK/items/022cfdfb7f6f92bf5f46

以前に以下の技術を習得しており、
GASを使い、LINE Botで送信した画像をOCRし、文字情報をLINE Botへ返信 + GoogleSpreadsheetへ記録する。
https://qiita.com/21HideK/items/4005559995ac2f270528

この二つを組み合わせると、疑似チャ〇ンジパッドがつくれるのでは?と思いチャレンジしました。

動作の仕組み

もじれん動作の仕組み.jpg

動作の様子

もじれん動作様子.gif

作成の流れ

1. ImgBBのアカウント作成
2. LINEbot作成、LIFFを作成
3. 以下のコードへ差し替える
4. LIFFへ登録、リッチメニューに登録
5. LIFFから送られた画像をOCR、文字を判定

作成手順

1. ImgBBのアカウント作成、 2. LINEbot作成、LIFFを作成

以下の記事を参照してください。
LIFFで描画(canvas)して、画像をLINEへ送信する。「お絵描きbot」
https://qiita.com/21HideK/items/022cfdfb7f6f92bf5f46

3. 以下のコードへ差し替える

① 作成したLIFFスターターアプリ内のコードを

それぞれ(CSS, HTML, JS)、以下のコードに丸ごと書き換える。

効果音は、効果音らぼ(https://soundeffect-lab.info/)から好きな音をダウンロード(100種類)。一つのフォルダ内にsound1.mp3 ~ sound100.mp3 までリネームしたファイルを入れ、フォルダをNetlifyへドラッグアンドドロップでアップロードし、URLをコピー(YOUR_NETLIFY_URL)。

001.png

YOUR_LIFF_ID
YOUR_IMGBB_API_KEY
YOUR_NETLIFY_URL

は、ご自分のものへ差し換えてください。

canvasへの描画方法は、
https://tonamao.hatenablog.com/entry/2019/03/03/180739
を参照し作成しました。

index.css
index.css
.color > a{
  display: inline-block;
  width: 40px;
  height: 40px;
}

* {
  box-sizing: border-box;
}

body{
  overflow: hidden; /* スクロールを無効にする */
  /* margin: 0; /* マージンをゼロにする */
  background: #CCCCCC;
  text-align: center;
  font-family: 'Courier New', sans-serif;
}

#board {
    padding: 0.2em 0.5em;
    margin: 2em auto;
    width: 320px;
    background: #79ffe0;
    box-shadow: 0px 0px 0px 10px #79ffd5;
    border: dashed 2px white;
}

.title{
    padding: 0.0em 0.5em;
    margin: 0.5em auto;
    width: 300px;
    background: #79ffe0;
    box-shadow: 0px 0px 0px 10px #79ffd5;
    border: dashed 2px white;
}
.title p {
    user-select: none;
    color: #636e72;
    margin: 0; 
    padding: 2px;
}

canvas{
  cursor: pointer;
  background: white;
  border-radius: 16px;
}

.black {
  display: inline-block;
  text-decoration: none;
  /*background: #87befd;*/
  background: #ffeaa7;
  width: 40px;
  height: 40px;
  line-height: 40px;
  border-radius: 50%;
  text-align: center;
  margin-right: 4px;
  margin-left: 4px;
  margin-top: 0px;
  margin-bottom: 0px;
  vertical-align: middle;
  overflow: hidden;
  transition: .4s;
  box-shadow:0 0 10px rgb(108, 108, 108);
 }
 
 .black i {
  /*ボタン自体*/
  vertical-align: middle;
  color: #272828;
  top: 9px;
  border-radius: 50%;
  font-size: 24px;
 }

 .black :hover{
  opacity:0.5;
  }

 .eraser {
  display: inline-block;
  text-decoration: none;
  /*background: #87befd;*/
  background: #ffeaa7;
  width: 40px;
  height: 40px;
  line-height: 40px;
  border-radius: 50%;
  text-align: center;
  margin-right: 12px;
  margin-left: 12px;
  margin-top: 0px;
  margin-bottom: 0px;
  vertical-align: middle;
  overflow: hidden;
  transition: .4s;
  box-shadow:0 0 10px rgb(108, 108, 108);
 }
 
 .eraser i {
  /*ボタン自体*/
  vertical-align: middle;
  color: #636e72;
  top: 9px;
  border-radius: 50%;
  font-size: 24px;
 }

 .eraser :hover{
  opacity:0.5;
  }

 .clear {
  display: inline-block;
  text-decoration: none;
  /*background: #87befd;*/
  background: #ffeaa7;
  width: 40px;
  height: 40px;
  line-height: 40px;
  border-radius: 50%;
  text-align: center;
  margin-right: 12px;
  margin-left: 12px;
  margin-top: 4px;
  margin-bottom: 4px;
  vertical-align: middle;
  overflow: hidden;
  transition: .4s;
  box-shadow:0 0 10px rgb(108, 108, 108);
 }
 
 .clear i {
  /*ボタン自体*/
  vertical-align: middle;
  color: #636e72;
  top: 9px;
  border-radius: 50%;
  font-size: 24px;
 }

 .clear :hover{
  opacity:0.5;
  }

.send{
display: flex;
justify-content: center;
}

  .button {
  width:100px;
  height:50px;
  font-family:Impact;
  font-size:100%;
  text-align:center;
  box-shadow:0 0 10px rgb(108, 108, 108);
  border-radius:20px;
  background-color:rgb(245, 227, 123);
}

.button:hover{
opacity:0.8;
}

.kanji {
  width:40px;
  height:20px;
  font-size:100%;
  text-align:center;
  margin-top: 10px;
  margin-bottom: 5px;
  box-shadow:0 0 10px rgb(15, 252, 70);
  border-radius:10px;
  margin-left: auto;
  margin-right: auto;
}

.smalltitle {
  margin:auto;
  text-align:center;
  
}

.hiragana, .katakana, .kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6{
  width:80px;
  height:30px;
  font-size:100%;
  text-align:center;
  box-shadow:0 0 10px rgb(108, 108, 108);
  border-radius:10px;
}

.hiragana, .katakana, .kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6:hover{
  opacity:0.8;
 }

.hiragana {
   background-color:rgb(0, 255, 0);
 }

.katakana {
   background-color:rgb(0, 255, 255);
}

.kanji_1, .kanji_2, .kanji_3, .kanji_4, .kanji_5, .kanji_6{
   background-color:rgb(255, 192, 203);
}

.kanji_4, .kanji_5, .kanji_6{
   background-color:rgb(255, 165, 0);
}

index.html
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="stylesheet" href="index.css" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
    <title>お絵描き</title>
      <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  </head>

  <body>
        <div class="title">
          <p>もじれん</p>
        </div>

        <div id="board">
          <canvas id="canvas" width="300px" height="300px"></canvas>
        </div>

        <div class="word">
          <div class="kana">
            <button class="hiragana" id="hiragana" onclick="hiragana()">ひらがな</button>
            <button class="katakana" id="katakana" onclick="katakana()">カタカナ</button>
          </div>

          <div class = "kanji">
            <a class="smalltitle" id="smalltitle">漢字</a><br>
          </div>
          <div class="kanji_low">
            <button class="kanji_1" id="kanji_1" onclick="kanji01()">1年生</button>
            <button class="kanji_2" id="kanji_2" onclick="kanji02()">2年生</button>
            <button class="kanji_3" id="kanji_3" onclick="kanji03()">3年生</button>
          </div>
          
          <div class="kanji_hight">
            <button class="kanji_4" id="kanji_4" onclick="kanji04()">4年生</button>
            <button class="kanji_5" id="kanji_5" onclick="kanji05()">5年生</button>
            <button class="kanji_6" id="kanji_6" onclick="kanji06()">6年生</button>
        </div>
      </div>

       <div class="option">
        <a href="#" id="black" class="black" data-color="0, 0, 0, 1" data-bold="5">
          <i class="fas fa-paint-brush fa-3x"></i>
        </a>
        <a href="#" id="eraser" class="eraser" data-color="255, 255, 255, 1" data-bold="20">
          <i class="fas fa-eraser fa-3x"></i>
        </a>

          <a href="#" id="clear" class="clear">
            <i class="fas fa-undo-alt fa-3x"></i>
          </a>
       </div>


        <div class="send">
          <button class="button" onclick="uploadAndSendToLINE()">Judge!</button>
        </div>
        
        <audio id="Sound_effect">
          <source id="Sound_kinds" class="Sound_kinds" src="" type="audio/mp3">
       </audio>

      <script>
        window.onload = initializeLIFF;

        function initializeLIFF() {
          liff.init({
              liffId: 'YOUR_LIFF_ID' // あなたのLIFFアプリのIDに置き換えてください
          })
          .then(() => {
              console.log("LIFF initialization successful");
          })
          .catch((err) => {
              console.error("LIFF initialization failed", err);
          });
        }

          // canvas
          var canvas = document.getElementById('canvas');
          var ctx = canvas.getContext('2d');
      
          // 変数宣言
          const cnvWidth = 300;
          const cnvHeight = 300;
          var cnvColor = "0, 0, 0, 1";  // 線の色
          var cnvBold = 5;  // 線の太さ
          var drawing = false; // 描画中フラグ
          var bgColor = "#ffffff"; //開いた時の最初の背景色(白)

          // canvasの背景色を設定(指定がない場合にjpeg保存すると背景が黒になる)
          setBgColor();
                
          // canvas上でのイベント
          canvas.addEventListener('mousedown', startDrawing);
          canvas.addEventListener('mouseup', stopDrawing);
          canvas.addEventListener('mousemove', draw);
          canvas.addEventListener('touchstart', startDrawing);
          canvas.addEventListener('touchend', stopDrawing);
          canvas.addEventListener('touchmove', draw);
      
	  var netlify_url ="YOUR_NETLIFY_URL"; //YOUR_NETLIFY_URLを書き換えてください。

      //ひらがなボタン
      function hiragana(){
          document.getElementById("hiragana").style.color = "white";
          document.getElementById("hiragana").style.background= "blue";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound1.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", 
            "", "", "", "", "", 
            "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          // Canvasに文章を表示
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();

          // 文字のスタイルを変更
          ctx.font = "20px Arial";  // 文字のサイズを大きく
          ctx.fillStyle = "red"; // sentence1の文字を赤に
          ctx.fillText(sentence1, 10, 30);

          ctx.fillStyle = "#000"; //sentence2の文字を黒に
          ctx.font = "14px Arial";  // 文字のサイズを小さく
          ctx.fillText(sentence2, 70, 30);      
      };

      //カタカナボタン
      function katakana(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "white";
          document.getElementById("katakana").style.background= "blue";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound2.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", "", "", 
            "", "", "", 
            "", "", "", "", "", 
            "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      //漢字1年生ボタン
      function kanji01(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "white";
          document.getElementById("kanji_1").style.background= "blue";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound3.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      //漢字2年生ボタン
      function kanji02(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "white";
          document.getElementById("kanji_2").style.background= "blue";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound4.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "西", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };


      //漢字3年生ボタン
      function kanji03(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "white";
          document.getElementById("kanji_3").style.background= "blue";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound5.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "使", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "宿", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "調", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      //漢字4年生ボタン
      function kanji04(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "white";
          document.getElementById("kanji_4").style.background= "blue";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound6.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "便", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      //漢字5年生ボタン
      function kanji05(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "white";
          document.getElementById("kanji_5").style.background= "blue";
          document.getElementById("kanji_6").style.color = "black";
          document.getElementById("kanji_6").style.background= "orange";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound7.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "退", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "貿", "", "", "", "", "綿", "", "", 
          "", "", "", "", ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      //漢字6年生ボタン
      function kanji06(){
          document.getElementById("hiragana").style.color = "black";
          document.getElementById("hiragana").style.background= "lime";
          document.getElementById("katakana").style.color = "black";
          document.getElementById("katakana").style.background= "aqua";
          document.getElementById("kanji_1").style.color = "black";
          document.getElementById("kanji_1").style.background= "pink";
          document.getElementById("kanji_2").style.color = "black";
          document.getElementById("kanji_2").style.background= "pink";
          document.getElementById("kanji_3").style.color = "black";
          document.getElementById("kanji_3").style.background= "pink";
          document.getElementById("kanji_4").style.color = "black";
          document.getElementById("kanji_4").style.background= "orange";
          document.getElementById("kanji_5").style.color = "black";
          document.getElementById("kanji_5").style.background= "orange";
          document.getElementById("kanji_6").style.color = "white";
          document.getElementById("kanji_6").style.background= "blue";

          document.getElementById("Sound_kinds").src = netlify_url + "/sound8.mp3";
          document.getElementById("Sound_effect").load(); 
          document.getElementById("Sound_effect").play();

          var wordList = [
          "", "", "", "", "", "", "沿", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "姿", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          "", "", "", "", "", "", "", "", "", "", 
          ""
          ];

          var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];

          // 文章の組み立て
          var sentence1 = '' + selectedWord + '';
          var sentence2 = 'を書いてください。';

          ctx.clearRect(0, 0, canvas.width, canvas.height);
          setBgColor();
          ctx.font = "20px Arial";
          ctx.fillStyle = "red";
          ctx.fillText(sentence1, 10, 30);
          ctx.fillStyle = "#000";
          ctx.font = "14px Arial";
          ctx.fillText(sentence2, 70, 30);
      };

      // 描画処理
      function draw(e) {
        if (!drawing) return;

        var x, y;
        if (e.type.startsWith('touch')) {
          x = e.touches[0].clientX - canvas.offsetLeft;
          y = e.touches[0].clientY - canvas.offsetTop;
        } else {
          x = e.offsetX;
          y = e.offsetY;
        }

          if (drawing) {
            ctx.lineTo(x, y);
            ctx.stroke();
          }
        }

      // 描画開始
      var lastX = 0;
      var lastY = 0;
      var x, y;

      function startDrawing(e) {
          drawing = true;
        
        if (e.type.startsWith('touch')) {
          x = e.touches[0].clientX - canvas.offsetLeft;
          y = e.touches[0].clientY - canvas.offsetTop;
          lastX = e.touches[0].clientX - canvas.getBoundingClientRect().left;
          lastY = e.touches[0].clientY - canvas.getBoundingClientRect().top;

        } else {
          x = e.offsetX;
          y = e.offsetY;
          lastX = e.clientX - canvas.getBoundingClientRect().left;
          lastY = e.clientY - canvas.getBoundingClientRect().top;
        }
        
          ctx.lineWidth = cnvBold;
          ctx.strokeStyle = 'rgba(' + cnvColor + ')';


          ctx.beginPath();
          ctx.lineCap = "round";
          ctx.moveTo(x, y);
        
      }

      // 描画終了
      function stopDrawing() {
        drawing = false;
      }


      // 黒線描画
      $("#black").click(function () {
        cnvColor = $(this).data("color");
        ctx.strokeStyle = 'rgba(' + cnvColor + ')';
        cnvBold = $(this).data("bold");
         return false;
      });
      // 消しゴム
      $("#eraser").click(function () {
        cnvColor = $(this).data("color");
        ctx.strokeStyle = 'rgba(' + cnvColor + ')';
        cnvBold = $(this).data("bold");
         return false;
      });

      // 描画クリア
      $("#clear").click(function () {
        ctx.clearRect(0, 0, cnvWidth, cnvHeight);
        setBgColor();
      });

 
      function setBgColor() {
        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, cnvWidth, cnvHeight);
          
      }

          // LINEへ描画したものを画像として送信する
          function uploadAndSendToLINE() {
              // LIFFが初期化されているか確認
              if (!liff.isInClient()) {
                  alert('This app must be viewed in the LINE app.');
                  return;
              }

              // Canvasから画像データを取得
              var imageDataURL = canvas.toDataURL();
              // 画像データをBase64に変換
              var base64Image = imageDataURL.replace(/^data:image\/(png|jpg);base64,/, '');

              // 画像をImgBBにアップロード
              // YOUR_IMGBB_API をあなたのImgBB APIに置き換えてください
              fetch('https://api.imgbb.com/1/upload?key=YOUR_IMGBB_API', {
                  method: 'POST',
                  body: new URLSearchParams({ image: base64Image, album: 'drawing' }),
                  headers: {
                      'Content-Type': 'application/x-www-form-urlencoded'
                  }
              })
              .then(response => response.json())
              .then(data => {
                var photoURL = data.data.url;
                var last_position = photoURL.indexOf('.png') - 17;
                var number = photoURL.substr(17, last_position);

                  // アップロード成功時にLINEに送信
                  sendImageMessage(number, data.data.url);
              })
              .catch(error => {
                  console.error('Error uploading image', error);
              });
          }

          function sendImageMessage(number, imageUrl) {
              // 画像のURLをLINEに送信
              liff.sendMessages([
                  {
                      type: 'image',
                      originalContentUrl: imageUrl,
                      previewImageUrl: imageUrl
                  },
                  {
                      type: "text",
                      text: number
                  }
              ])
              .then(() => {
                // 1秒ごとにカウントダウンを表示
                var count = 10;
                var countdownInterval = setInterval(function() {
                  if (count == 10){
                    var count_A = "";
                  }else if(count == 9){
                    var count_A = "";
                  }else if(count == 8){
                    var count_A = "";
                  }else if(count == 7){
                    var count_A = "";
                  }else if(count == 6){
                    var count_A = "";
                  }else if(count == 5){
                    var count_A = "";
                  }else if(count == 4){
                    var count_A = "";
                  }else if(count == 3){
                    var count_A = "";
                  }else if(count == 2){
                    var count_A = "";
                  }else if(count == 1){
                    var count_A = "";
                  }

                  if (count >= 1) {
                    ctx.clearRect(0, 0, cnvWidth, cnvHeight);
                    ctx.font = "150px Arial";
                    ctx.fillStyle = "blue";
                    ctx.textAlign = "center";
                    ctx.fillText(count_A, cnvWidth / 2, cnvHeight *2/ 3);
                    count--;

                    var randomNumber = Math.floor(Math.random() * 100) + 1;
                      //YOUR_NETLIFY_URL:Netlifyにアップロードした音声ファイルの入ったフォルダのURLを入れてください。
                    document.getElementById("Sound_kinds").src = netlify_url + "/sound" + randomNumber + ".mp3";
                    document.getElementById("Sound_effect").load(); 
                    document.getElementById("Sound_effect").play();

                  } else {
                    clearInterval(countdownInterval);
                    ctx.clearRect(0, 0, cnvWidth, cnvHeight);
                    ctx.font = "48px Arial";
                    ctx.fillStyle = "red";
                    ctx.textAlign = "center";
                    ctx.fillText("結果発表!", cnvWidth / 2, cnvHeight / 2);
                    setTimeout(function() {
                      liff.closeWindow();
                    }, 3000); // 3秒後にLIFFを閉じる
                  }
                }, 1000); // 1秒ごとに実行
              })
              .catch((err) => {
                  console.error('Error sending image', err);
              });
          }

      </script>
  </body>
</html>

index.js
index.js
import './index.css';
import liff from '@line/liff'

document.addEventListener("DOMContentLoaded", function() {
  liff
    .init({ liffId: process.env.LIFF_ID })
    .then(() => {
        console.log("Success! you can do something with LIFF API here.")
    })
    .catch((error) => {
        console.log(error)
    })
});

② 再度、Netlifyへデプロイ

LINE公式サイト
https://developers.line.biz/ja/docs/liff/trying-liff-app/#how-to-start-liff-starter-app
の通りに、再度デプロイ。

ターミナル
netlify build
netlify deploy --prod

4. LIFFへ登録、リッチメニューに登録

https://qiita.com/21HideK/items/4005559995ac2f270528
の5.②を参考に、作成。

LIFF URL(2.②B.でコピーしたもの)を登録し、LINEbotのリッチメニューからLIFFを開けるようにする。

5. LIFFから送られた画像をOCR、文字を判定

ここからは、
GASを使い、LINE Botで送信した画像をOCRし、文字情報をLINE Botへ返信 + GoogleSpreadsheetへ記録する。
https://qiita.com/21HideK/items/4005559995ac2f270528
を参照にしながら作ります。

1.LINE Developersコンソール内での準備~5.LINE Botの設定 の通りに作ります。
3.⑥GASへコードを書きこむ は、以下のコードをコピー&ペーストしてください。

 判定を返信するFlex menuの画像を用意。成功、読めない、失敗にそれぞれ10枚の画像を用意、ランダムに表示させる。
 "seikou", "yomenai", "sippai"というフォルダを作成、それぞれにimage_seikou1~10.png、image_yomenai1~10.png、image_sippai1~10.pngとリネームしたファイルを用意。"seikou", "yomenai", "sippai"フォルダを一つのフォルダに入れ、そのフォルダをNetlifyへドラッグアンドドロップでアップロードし、URLをコピー(YOUR_NETLIFY_URL)。(効果音のフォルダと同じでも可)

YOUR_ACCESS_TOKEN
YOUR_DRIVE_FOLDER_ID
YOUR_SPREADSHEET_ID
YOUR_NETLIFY_URL
YOUR_LIFF_URL

は、ご自分のものへ差し換えてください。

GAS
Google App Script
//★★LINE Messaging APIのチャネルアクセストークン★★
var LINE_ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"; //自分のline アクセストークンを入れてください。

//★★画像を保存するフォルダーID★★
var GOOGLE_DRIVE_FOLDER_ID = "YOUR_DRIVE_FOLDER_ID"; //自分のgoogle Drive idを入れてください。

  const search_spreadsheet_id = "YOUR_SPREADSHEET_ID"; //自分のスプレッドシートIDを入れてください。
  const targetSheet = SpreadsheetApp.openById(search_spreadsheet_id).getSheetByName("シート1");

  //ファイル名に使う現在日時をMomentライブラリーを使って取得
  var date = Moment.moment(); //現在日時を取得
  var formattedDate = date.format("YYYYMMDD_HHmmss");

//LINE Messaging APIからPOST送信を受けたときに起動する
// e はJSON文字列
function doPost(e){
  if (typeof e === "undefined"){
    //eがundefinedの場合動作を終了する
    return;
  } 

  //JSON文字列をパース(解析)し、変数jsonに格納する
  var json = JSON.parse(e.postData.contents);

  //受信したメッセージ情報を変数に格納する
  var reply_token = json.events[0].replyToken; //reply token
  var message = json.events[0].message.text;
  var messageId = json.events[0].message.id; //メッセージID
  var messageType = json.events[0].message.type; //メッセージタイプ

  //LINEで送信されたものが画像以外の場合、LINEで返信し動作を終了する
  if(messageType === "text"){

     //1秒待つ関数を、A3セルが"img"になるまで、20回繰り返す。
        for (let i = 0; i < 20; i++){
          var startMsec = new Date();
          // 指定ミリ秒間だけループさせる(CPUは常にビジー状態)
          while (new Date() - startMsec < 1000);
          i = i+1;

          if(targetSheet.getRange(3, 1).getValue() == "img") {
            break;
          }
        }

      targetSheet.getRange(3, 1).setValue("");
      var imgBBUrl = "https://i.ibb.co/" +  message + ".png";
      getImage(imgBBUrl, reply_token);

  }else if(messageType === "image"){
    targetSheet.getRange(3, 1).setValue("img");
    SpreadsheetApp.flush(); //シートの再描画を行い、スプレッドシート関数の再計算を実行

  }else {
    var messageNotImage = "もじれんメニューを使ってください"
    //変数reply_tokenとmessageNotImageを関数sendMessageに渡し、sendMessageを起動する
    sendMessage(reply_token, messageNotImage);
    return;
  }
 }

//Blob形式で画像を取得する
function getImage(imgBBUrl, reply_token){
  try {
  var response = UrlFetchApp.fetch(imgBBUrl);
  var imgblob = response.getBlob();
  
  var folder = DriveApp.getFolderById(GOOGLE_DRIVE_FOLDER_ID);
  folder.createFile(imgblob);

    for (let i = 0; i < 1; i++){
      var startMsec = new Date();
      while (new Date() - startMsec < 2000);
      i = i+1;
    }

  //変数imageBlobとreply_tokenを関数saveImageに渡し、saveImageを起動する
  get_ocr_Image(reply_token)

  } catch(e) {
  //例外エラーが起きた時にログを残す
  Logger.log(e.message);
  }
}

//画像をGoogle Driveのフォルダーに画像を保存(アップロード)、OCRをかけテキストを取得。
//保存された画像、作成されたドキュメントファイルは残す。
//OCRで得られたテキストをLine Botへ返信する。
function get_ocr_Image(reply_token){
  try{

      //ここからOCRをかけていく
    let a = Drive.Children.list(GOOGLE_DRIVE_FOLDER_ID)
    
    // 設定事項を書いていく

    let resource = {
      title: "OCR結果" + formattedDate // 生成されるGoogleドキュメントのファイル名
    };
    let option = {
      "ocr": true,// OCRを行うかの設定です
      "ocrLanguage": "ja",// OCRを行う言語の設定です
    }
    
    // 取得したファイル一覧の最初のもののfileIdを変数に格納します
    let fileId = a.items[0].id
    // 指定したfileIdのファイルをコピーします
    let image = Drive.Files.copy(resource, fileId, option)
    // コピー先ファイルにはOCRのデータが含まれているのでテキストを取得します
    var text_O = DocumentApp.openById(image.id).getBody().getText();

    var wrihgt_position = text_O.indexOf('') +2;
    var exa = text_O.substring( 2, 3 );
    var wright = text_O.substring( wrihgt_position, wrihgt_position +1 );
    targetSheet.getRange(4, 1).setValue(exa);
    targetSheet.getRange(5, 1).setValue(wright);

    // アップロードした写真、作成したOCRファイルを削除する。
    Drive.Files.remove(image.id) //作成したOCRファイルを削除
    Drive.Files.remove(fileId)   //アップロードした写真を削除
    
    // OCRで得られたテキストを、Line Botへ返信する。
    if(exa == wright){
      // 用意されたリストからランダムに単語を選択
      var wordList = [
    "すばらしい!", "天才か‼", "才能あり!", "上手!", "とっても上手!", "めちゃくちゃ上手!", "良いね!", "上手!天才か!", "とても上手! 天才か!", "うまぁーーーーい!", "いいんじゃない!"];
      var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
      replymenu1(reply_token, selectedWord);

    }else {
      if(wright == ""){
        var re_message = "すみません、私には読めません…";
        replymenu2(reply_token, re_message);
        
      }else {
      // 用意されたリストからランダムに単語を選択
      var wordList = [
      "おしい!", "そうだねぇ。", "もう少し!", "もうちょっと!", "良いけど…", "うーん⁉", "ううーん?", "これはなんでしょうか?", "まあ、そうなんだけど。", "おーーーい!", "おや?"];
      var selectedWord = wordList[Math.floor(Math.random() * wordList.length)];
      var re_message1 = selectedWord;
      var re_message2 = "私はこう読めます。";
      var re_message3 = "" + wright + "";
      replymenu3(reply_token, re_message1, re_message2, re_message3);
      }
    }
    
  } catch(e){
    //例外エラーが起きた時にログを残す
    Logger.log(e)
  }
}

function replymenu1(reply_token, re_message){
                  var randomNumber = Math.floor(Math.random() * 10) + 1;

                  var menu1 = [{
                      'type':'flex',  //ここの宣言が必須
                      'altText':'this is a flex message',
                      //↓このcontentsの部分にSimulatorのJSONをコピー
                      'contents': 
                        {
                        "type": "bubble",
                        "size": "kilo",
                        "hero": {
                          "type": "image",
                          "url": "YOUR_NETLIFY_URL/seikou/image_seikou" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
                          "margin": "none",
                          "size": "full",
                          "aspectRatio": "20:8"
                        },
                        "body": {
                          "type": "box",
                          "layout": "vertical",
                          "contents": [
                            {
                              "type": "text",
                              "text": re_message,
                              "weight": "bold"
                            }
                          ],
                          "alignItems": "center"
                        },
                        "footer": {
                          "type": "box",
                          "layout": "vertical",
                          "spacing": "md",
                          "contents": [
                            {
                              "type": "box",
                              "layout": "vertical",
                              "contents": [
                                {
                                  "type": "text",
                                  "text": "つづける",
                                  "size": "15px",
                                  "weight": "bold"
                                }
                              ],
                              "margin": "none",
                              "background": {
                                "type": "linearGradient",
                                "angle": "0deg",
                                "startColor": "#98fb98",
                                "endColor": "#ffffff"
                              },
                              "width": "180px",
                              "alignItems": "center",
                              "cornerRadius": "10px",
                              "action": {
                                "type": "uri",
                                "label": "action",
                                "uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
                              },
                              "spacing": "none",
                              "offsetBottom": "lg",
                              "height": "40px",
                              "justifyContent": "center"
                            }
                          ],
                          "flex": 0,
                          "alignItems": "center"
                        }
                      }
                      }]  
                sendMessage2(reply_token, menu1)
};


function replymenu2(reply_token, re_message){
                  var randomNumber = Math.floor(Math.random() * 10) + 1;

                  var menu2 = [{
                      'type':'flex',  //ここの宣言が必須
                      'altText':'this is a flex message',
                      //↓このcontentsの部分にSimulatorのJSONをコピー
                      'contents': 
                        {
                        "type": "bubble",
                        "size": "kilo",
                        "hero": {
                          "type": "image",
                          "url": "YOUR_NETLIFY_URL/yomenai/image_yomenai" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
                          "margin": "none",
                          "size": "full",
                          "aspectRatio": "20:8"
                        },
                        "body": {
                          "type": "box",
                          "layout": "vertical",
                          "contents": [
                            {
                              "type": "text",
                              "text": re_message,
                              "weight": "bold"
                            }
                          ],
                          "alignItems": "center"
                        },
                        "footer": {
                          "type": "box",
                          "layout": "vertical",
                          "spacing": "md",
                          "contents": [
                            {
                              "type": "box",
                              "layout": "vertical",
                              "contents": [
                                {
                                  "type": "text",
                                  "text": "つづける",
                                  "size": "15px",
                                  "weight": "bold"
                                }
                              ],
                              "margin": "none",
                              "background": {
                                "type": "linearGradient",
                                "angle": "0deg",
                                "startColor": "#c7dc68",
                                "endColor": "#ffffff"
                              },
                              "width": "180px",
                              "alignItems": "center",
                              "cornerRadius": "10px",
                              "action": {
                                "type": "uri",
                                "label": "action",
                                "uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
                              },
                              "spacing": "none",
                              "offsetBottom": "lg",
                              "height": "40px",
                              "justifyContent": "center"
                            }
                          ],
                          "flex": 0,
                          "alignItems": "center"
                        }
                      }
                      }]  
                sendMessage2(reply_token, menu2)
};



function replymenu3(reply_token, re_message1, re_message2, re_message3){
                  var randomNumber = Math.floor(Math.random() * 10) + 1;

                  var menu3 = [{
                      'type':'flex',  //ここの宣言が必須
                      'altText':'this is a flex message',
                      //↓このcontentsの部分にSimulatorのJSONをコピー
                      'contents': 
                        {
                        "type": "bubble",
                        "size": "kilo",
                        "hero": {
                          "type": "image",
                          "url": "YOUR_NETLIFY_URL/sippai/image_sippai" + randomNumber + ".png", //YOUR_NETLIFY_URLにご自分のnetlify名を入れてください。
                          "margin": "none",
                          "size": "full",
                          "aspectRatio": "20:8"
                        },
                        "body": {
                          "type": "box",
                          "layout": "vertical",
                          "contents": [
                            {
                              "type": "text",
                              "text": re_message1,
                              "weight": "bold"
                            },
                                                        {
                              "type": "text",
                              "text": re_message2,
                              "weight": "bold"
                            },
                                                        {
                              "type": "text",
                              "text": re_message3,
                              "weight": "bold"
                            }
                          ],
                          "alignItems": "center"
                        },
                        "footer": {
                          "type": "box",
                          "layout": "vertical",
                          "spacing": "md",
                          "contents": [
                            {
                              "type": "box",
                              "layout": "vertical",
                              "contents": [
                                {
                                  "type": "text",
                                  "text": "つづける",
                                  "size": "15px",
                                  "weight": "bold"
                                }
                              ],
                              "margin": "none",
                              "background": {
                                "type": "linearGradient",
                                "angle": "0deg",
                                "startColor": "#ff00ff",
                                "endColor": "#ffffff"
                              },
                              "width": "180px",
                              "alignItems": "center",
                              "cornerRadius": "10px",
                              "action": {
                                "type": "uri",
                                "label": "action",
                                "uri": "YOUR_LIFF_URL" //先ほど作成したLIFFのURLを入れる
                              },
                              "spacing": "none",
                              "offsetBottom": "lg",
                              "height": "40px",
                              "justifyContent": "center"
                            }
                          ],
                          "flex": 0,
                          "alignItems": "center"
                        }
                      }
                      }]  
                sendMessage2(reply_token, menu3)
};



//ユーザーにメッセージを送信する
function sendMessage(reply_token, text){
  //返信先URL
  var replyUrl = "https://api.line.me/v2/bot/message/reply";

  var headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + LINE_ACCESS_TOKEN
  };
  
  var postData = {
    "replyToken": reply_token,
    "messages": [{
                  "type": "text",
                  "text": text
                  }]
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  //LINE Messaging APIにデータを送信する
  UrlFetchApp.fetch(replyUrl, options);
}

function sendMessage2(reply_token, menu_message){
  //返信先URL
 var replyUrl = 'https://api.line.me/v2/bot/message/reply';

  var headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + LINE_ACCESS_TOKEN
  };
  
  var postData = {
    "replyToken": reply_token,
    "messages": menu_message
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  //LINE Messaging APIにデータを送信する
  UrlFetchApp.fetch(replyUrl, options);
}


工夫ポイント、苦労したポイント

●画像の左上の文字列は、結果照合のために入れています。
画像全体にOCRをかけ、 ”2文字目” と、 ”。の後の文字” が同じであるかを照合し、同じであれば正解、違っていれば不正解と読み取れた文字を、読み取れない(書いた文字がないと判断される)場合は読み取れないメッセージを返すようにしています。
LINEへのテキスト返信でも同様の照合は可能と考えますが、お題と答えを同じ画像に残すと後で見て分かりやすいかなと思い、今回の形式にしています。

●画像の後の文字列(テキスト)送信は、imgBBの画像URLの一部になります。
①LIFF描いた絵をimgBBへ送信、その画像URLをGASで取得simgBB⇒GoogleDiveへ送信
②LIFFで書いた絵を直接GoogleDriveへ送信

本当は、上記の①または②の方法ができればスマートなのですが、①はimgBBへ送信した画像からimgBBのURLを後から読み取る方法(GASで取得する方法)が分からない、②は方法が分からないので、送信時にLINE(その後ろで動くGAS)へ画像URL(LIFFで設定したimgBB画像URL)を送って再利用することにしました。

●画像に対しOCRをかけて返信するまでに10~20秒ほどかかる。
 これはネット環境やImgBB、GoogleDriveの応答の問題なので、改善は困難と考えました。そこで、時間稼ぎのため、LIFFを閉じるまでに10秒間カウント(効果音付き)としました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2