ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

GAS - QRコード生成ウェブアプリを作成

初めに

 GAS を使って、QRコードを生成する Web アプリを公開したので、紹介いたします。

機能

(使い方)

  • URLを入力し、ボタンを押すとQRコードを生成する
  • QRコードの色、背景色、サイズの設定を変更することができる
  • デフォルトの設定では、黒、白、200x200のQRコードが作成される

script.google.com

※GASでの公開のため、この Web アプリを利用するには Google アカウントにログインする必要があります。

コード全文

Code.gs
// Code.gs
function doGet() {
  return HtmlService.createTemplateFromFile('index')
    .evaluate()
    .setTitle('QRコード生成アプリ')
    .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

function getCustomQRCode(url, color, backgroundColor, size) {
  var apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?data=' + encodeURIComponent(url);

  if (color) {
    apiUrl += '&color=' + encodeURIComponent(color);
  }
  if (backgroundColor) {
    apiUrl += '&bgcolor=' + encodeURIComponent(backgroundColor);
  }
  if (size) {
    apiUrl += '&size=' + encodeURIComponent(size);
  }

  Logger.log(apiUrl);
  return apiUrl;
}

// ログ確認用
function logGetCustomQRCode()
{
  var url = "url";
  getCustomQRCode(url, "red", "blue", "300x300");
}
index.html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <title>QRコードクリエイト</title>

  <!-- Materialize CSS CDN -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">

  <!-- Font Awesome CDN -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">

  <!-- Pickr CSS CDN -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css"/> <!-- 'classic' theme -->

  <!-- 外部のスタイルシートを読み込む -->
  <?!= HtmlService.createHtmlOutputFromFile('style').getContent(); ?>
</head>

<body>
  <header>
    <h3 class="center-align" style="color: white">QRコードクリエイト</h3>
  </header>
  <div class="container">
    <form id="urlForm" class="col s12">
      <div class="row">
        <div class="input-field col s12">
          <input type="text" id="urlInput" class="validate" required>
          <label for="urlInput">URLを入力してください</label>
        </div>
      </div>
      <h6>各種設定を入力してください</h6>
      <p>デフォルト設定は色:黒、背景色:白、サイズ:200x200</p>
      <div class="row">
        <div class="input-field col s12">
        <h6></h6>
          <div class="color-picker-container" style="display: flex; align-items: center;">
            <div style="padding: 10px; border: 2px solid #000;">
              <input type="text" id="colorInput" class="validate" placeholder="色を選択">
            </div>
            <p id="colorRgb" style="margin-left: 10px;"></p>
          </div>
        </div>
      </div>
      <div class="row">
        <div class="input-field col s12">
          <h6>背景色</h6>
          <div class="color-picker-container" style="display: flex; align-items: center;">
            <div style="padding: 10px; border: 2px solid #000;">
              <input type="text" id="bgColorInput" class="validate" placeholder="背景色を選択">
            </div>
            <p id="bgColorRgb" style="margin-left: 10px;"></p>
          </div>
        </div>
      </div>
      <div class="row">
        <div class="input-field col s12">
          <h6>サイズ</h6>
          <input type="range" id="sizeSlider" min="10" max="1000" step="1" value="200">
          <output id="sizeValue">200x200</output>
        </div>
      </div>
      <div class="row">
        <div class="input-field col s12">
          <button class="btn waves-effect waves-light" type="submit">QRコードを生成</button>
        </div>
      </div>
    </form>
    
    <div class="row">
      <div id="qrCode" class="center-align"></div>
    </div>
  </div>


  <!-- Materialize JS CDN -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
  <!-- Font Awesome JS CDN -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js"></script>
  <!-- Pickr JS CDN -->
  <script src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js"></script>

  <script>
    let colorCode;
    let bgColorCode;

    document.getElementById('urlForm').addEventListener('submit', function(e) {
      e.preventDefault();
      var url = document.getElementById('urlInput').value;
      var color = document.getElementById('colorInput');
      var bgColor = document.getElementById('bgColorInput');
      var size = document.getElementById('sizeSlider').value;
      var sizeCode = size + "x" + size;

      generateQRCode(url, colorCode, bgColorCode, sizeCode);
    });

    function generateQRCode(url, color, bgColor, size) {
      google.script.run.withSuccessHandler(displayQRCode).getCustomQRCode(url, color, bgColor, size);
    }

    function displayQRCode(qrCodeUrl) {
      var qrCodeDiv = document.getElementById('qrCode');
      qrCodeDiv.innerHTML = '<img src="' + qrCodeUrl + '" alt="QR Code">';
    }

    document.addEventListener('DOMContentLoaded', function() {
    // 色を選択するinput要素を取得する
    const colorInput = document.getElementById('colorInput');
    const bgColorInput = document.getElementById('bgColorInput');

    const colorRgb = document.getElementById('colorRgb');
    const bgColorRgb = document.getElementById('bgColorRgb');

    // 初期値の入力
    colorRgb.textContent = "RGB:(0, 0, 0), #000000";
    bgColorRgb.textContent = "RGB:(255, 255, 255), #FFFFFF";

    // Pickrをインスタンス化する
    const pickr = Pickr.create({
      el: colorInput,
      theme: 'classic', // ピッカーのテーマを選択
      default: '#000000', // 初期の色を設定
      comparison: false,
      swatches: [
        '#000000', '#FFFFFF', '#FF0000', '#00FF00', '#0000FF' // 予め定義され たカラーパレット
      ],
      components: {
        preview: true,
        opacity: false,
        hue: true,
        interaction: {
          input: true,
          save: true
        }
      }
    });

    const pickrBg = Pickr.create({
      el: bgColorInput,
      theme: 'classic',
      default: '#FFFFFF',
      comparison: false,
      swatches: [
        '#000000', '#FFFFFF', '#FF0000', '#00FF00', '#0000FF'
      ],
      components: {
        preview: true,
        opacity: false,
        hue: true,
        interaction: {
          input: true,
          save: true
        }
      }
    });

    pickr.on('change', (color) => {
      const rgba = color.toRGBA();
      const rgb = `RGB:(${Math.round(rgba[0])}, ${Math.round(rgba[1])}, ${Math.round(rgba[2])}), ${color.toHEXA().toString()}`;  //末尾にカラーコードを表示
      colorCode = Math.round(rgba[0]) + "-" + Math.round(rgba[1]) + "-" + Math.round(rgba[2]);
      colorRgb.textContent = rgb;
    });

    pickrBg.on('change', (color) => {
      const rgba = color.toRGBA();
      const rgb = `RGB:(${Math.round(rgba[0])}, ${Math.round(rgba[1])}, ${Math.round(rgba[2])}), ${color.toHEXA().toString()}`;
      bgColorCode = Math.round(rgba[0]) + "-" + Math.round(rgba[1]) + "-" + Math.round(rgba[2]);
      bgColorRgb.textContent = rgb;
    });
    });

    document.addEventListener('DOMContentLoaded', function() {
      const sizeSlider = document.getElementById('sizeSlider');
      const sizeValue = document.getElementById('sizeValue');

      sizeSlider.addEventListener('input', function() {
      sizeValue.textContent = sizeSlider.value + "x" + sizeSlider.value;
    });
    });

  </script>
</body>
</html>
styleシート
<style>
header {
  background-color: #26a69a; /* ここに背景色のカラーコードを入力してください */
  padding: 20px; /* 必要に応じて余白を調整 */
}

.center-align {
  text-align: center;
}

.qr-code-container {
  position: relative;
  display: inline-block;
}
</style>

作成の動機

 URLをQRコード化する機会がありますが、一般に公開したくないURLをQRコード化する場合、ネット上にあるQRコード作成サイトを使うことは危険であるため、自分で作ってしまえばよいと思い、作成しました。

解説

QR code API を使ったQRコードの生成

 QR code API を使用し、URLからQRコードを作成しています。

goqr.me

// Code.gs から抜粋
function getCustomQRCode(url, color, backgroundColor, size) {
  var apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?data=' + encodeURIComponent(url);

  if (color) {
    apiUrl += '&color=' + encodeURIComponent(color);
  }
  if (backgroundColor) {
    apiUrl += '&bgcolor=' + encodeURIComponent(backgroundColor);
  }
  if (size) {
    apiUrl += '&size=' + encodeURIComponent(size);
  }

  Logger.log(apiUrl);
  return apiUrl;
}

 Code.gs の getCustomQRCode(url, color, backgroundColor, size) 関数では、フロントエンドから URL、色、背景色、サイズをパラメータとして取得し、apiURLを返しています。

<!-- index.html の <script> から抜粋 -->
document.getElementById('urlForm').addEventListener('submit', function(e) {
      e.preventDefault();
      var url = document.getElementById('urlInput').value;
      var color = document.getElementById('colorInput');
      var bgColor = document.getElementById('bgColorInput');
      var size = document.getElementById('sizeSlider').value;
      var sizeCode = size + "x" + size;

      generateQRCode(url, colorCode, bgColorCode, sizeCode);
    });

    function generateQRCode(url, color, bgColor, size) {
      google.script.run.withSuccessHandler(displayQRCode).getCustomQRCode(url, color, bgColor, size);
    }

    function displayQRCode(qrCodeUrl) {
      var qrCodeDiv = document.getElementById('qrCode');
      qrCodeDiv.innerHTML = '<img src="' + qrCodeUrl + '" alt="QR Code">';
    }

 フロントエンドでは、submit ボタンを押すと、イベントが発生し generateQRCode() を実行します。generateQRCode() では、先ほど紹介した Code.gs にある getCustomQRCode() を実行し、引数である apiUrl をdisplayQRCode() 関数のパラメータ(qrCodeUrl)として受け取ります。受け取った apiUrl を画像として表示します。

Pickr を使った色の取得

 Pickr を使って、下の画像のようにカラーピッカーを表示させ、選択した色のデータを取得することができます。

simonwep.github.io

 特筆すべき部分は次の2か所です。

<!-- index.html のカラーピッカー取得部分 -->
<input type="text" id="colorInput" class="validate" placeholder="色を選択">

<!-- 中略 -->

<!-- <Script> のPickrのインスタンス化部分 -->
 // Pickrをインスタンス化する
    const pickr = Pickr.create({
      el: colorInput,
      theme: 'classic', // ピッカーのテーマを選択
      default: '#000000', // 初期の色を設定
      comparison: false,
      swatches: [
        '#000000', '#FFFFFF', '#FF0000', '#00FF00', '#0000FF' // 予め定義され たカラーパレット
      ],
      components: {
        preview: true,
        opacity: false,
        hue: true,
        interaction: {
          input: true,
          save: true
        }
      }
    });

 通常の input の表示の仕方ではなく、カラーピッカーの形に表示されるのは、Pickr のインスタンス化の部分で設定されているからです。el で id を指定し、インスタンスの設定をしています。