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

最近、以下の技術を習得しました（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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165076/abd2d89d-671d-5792-1d4a-99c0aaa0b0ae.jpeg)


# 動作の様子
![もじれん動作様子.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165076/97ac4da0-c213-2181-8d1d-70377b2ca600.gif)


:::note
# 作成の流れ
**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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165076/2cfa59c4-ee1c-2518-ce41-5f61a6508ba2.png)


YOUR_LIFF_ID
YOUR_IMGBB_API_KEY
YOUR_NETLIFY_URL

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

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

<details><summary>index.css</summary><div>

```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);
}

```

</div></details>


<details><summary>index.html</summary><div>

```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>

```

</div></details>


<details><summary>index.js</summary><div>

```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)
    })
});

```

</div></details>

### ② 再度、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
を参照にしながら作ります。

１．LINE Developersコンソール内での準備～５．LINE Botの設定　の通りに作ります。
３．⑥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

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


<details><summary>GAS</summary><div>

```JS: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);
}


```

</div></details>


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


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

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

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