FileMaker×JavaScript 実践例　（１）下ごしらえ＋画像処理編

# はじめに
　この記事ではFileMaker×JavaScriptの実践例をご紹介します。
　動作環境はFileMaker Pro v19.1.2以降（Mac / Windows）を対象とします。

　この記事は
　**Qiita Engineer Festa 2022 「Claris FileMaker で作った App を JavaScript で拡張したらどうなる？！」**
　https://qiita.com/official-campaigns/engineer-festa/2022
　に参加しています。
# やってみること
- FileMaker ProのWebビューア上でJavaScriptを実行するための下地づくり
- JavaScriptを利用してFileMaker Pro単体ではできない画像データの加工に挑戦
　ここでは、オブジェクトフィールドにあるカラー画像をグレースケール画像に変換します。

# まずは下ごしらえ
　JavaScriptをFileMakerファイル内で記述ことも可能ですが、FileMakerの開発UIはJavaScriptのために最適化されていないので、いろいろと面倒です。
　ここではFileMakerのファイルとJavaScriptのソースファイルを分離した方法をご紹介します。
　VS Codeなどお好みの編集環境がそのまま使えるのでおすすめです。
#### 手順
- FileMaker Proでファイルを新規作成します。（fm_js.fmp12）
- FileMakerでレイアウト上にWebビューアを配置し名前をつけます。（wv）
- Webビューアの設定ダイアログを開き「JavaScriptによるFileMakerスクリプトの実行を許可」を有効にします。
- Webアドレスは空欄がよいでしょう。その他の設定はお好みでOKです。
![スクリーンショット 2022-07-12 9.33.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/e3f9d1d9-b5a6-419f-980c-eb42b3519bfb.png)
- FileMakerのファイルと同じフォルダ内にJavaScript（を含むHTML）のソースファイルを作成します。（fm_js_source.html）
```html:fm_js_source.html
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p id = "p">JS未実行：これが見えたら失敗です</p>

    <script>
        const p = document.getElementById("p");
        p.textContent = "Hello FileMaker x JavaScript";
    </script>
</body>
</html>
```

- FileMakerでこのHTMLファイルを読み込んでWebビューアに表示するスクリプトを作成します。（load_JS）
![スクリーンショット 2022-07-12 9.16.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/2f1c47b5-9a93-0379-8de4-20a723ac4412.png)
　スクリプトを実行してWebビューアに「Hello FileMaker x JavaScript」と表示されたら、下地づくりまでは成功です。
# 画像処理に挑戦
　さきほどまでのファイルをそのまま変更していきます。
#### 手順１：フィールドとレイアウトの定義
- フィールド定義します。
　元のカラー画像とグレー変換画像の出力用の２つのオブジェクトフィールドを設定します。
![スクリーンショット 2022-07-12 11.06.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/7910c5b3-eb6e-dc6b-929e-707036122670.png)
-作成した２つのフィールドをレイアウトにも配置しておきます。
![スクリーンショット 2022-07-12 13.43.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/f194a69d-f76e-801b-107d-df4cc4399faf.png)

#### 手順２：コーディング
　全体のロジックとしては、FileMakerスクリプトとJavaScriptをそれぞれ書いて連携させていきます。FileMakerからはJavaScript内の関数を、JavaScriptからはFileMakerのスクリプトをそれぞれ呼び合うのですが、一つ注意すべき点があります。
それは、**「FileMaker→JavaScript ・ JavaScript→FileMaker どちらも呼びっぱなしで戻り値を受け取る仕組みがない」** ということです。
- 関数であって関数にあらず。（関数呼び出しというよりはイベントトリガーを飛ばし合う関係）
- 引数はあるが戻り値はない。
書き始める前にこれを肝に銘じておきましょう。

　実際の処理の進行に沿って書いていきます。
- FileMakerスクリプトを作成（convert_image）
![スクリーンショット 2022-07-12 15.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/3bab94d3-5aca-f0c9-f5e0-b36937074c5c.png)
　JavaScriptに渡す引数はテキスト形式にする必要があるので、オブジェクトフィールドの画像データはbase64形式に変換します。さらに改行コード（CR LF）をSubstitute関数で取り除いておきます。
　「WebビューアでJavaScriptを実行」スクリプトステップでデータ送信＆JS実行。結果は別のスクリプト宛に届くことを信じてこのスクリプトはこのまま終了です。

- JavaScript（を含むHTML）ソースファイル（fm_js_source.html）を以下のコードで置き換えます。
```html:fm_js_source.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");

        function convertImage(width, height, img) {
            //引数データを画像に展開
            ctx.width = width;
            ctx.height = height;
            canvas.width = width;
            canvas.height = height;
            const image = document.createElement('img');
            image.src = img;
            image.addEventListener("load",  () => {
                ctx.drawImage(image, 0, 0);
                processImage(width, height);
            });
        }

        function processImage(width, height) {
            //グレースケールに変換
            const imageData = ctx.getImageData(0, 0, width, height);
            const result = ctx.createImageData(width, height)
            const r = 0, g = 1, b = 2, a = 3;
            const NofPixels = width * height;

            for (let i = 0; i < NofPixels; i++) {
                const index = i * 4;
                let y = 0.2126 * imageData.data[index + r]
                      + 0.7152 * imageData.data[index + g]
                      + 0.0722 * imageData.data[index + b];
                y = Math.round(y);
                result.data[index + r] = y;
                result.data[index + g] = y;
                result.data[index + b] = y;
                result.data[index + a] = imageData.data[index + a]; //alpha
            }
            ctx.putImageData(result, 0, 0);

            //JPEGデータを生成しFileMakerに返送
            const jpgImg = canvas.toDataURL('image/jpeg', 0.0);
            FileMaker.PerformScriptWithOption('return', jpgImg, 0);
        }
    </script>
</body>
</html>
```
　今回はJavaScriptプログラミングは本題ではないので、詳細な解説は省きますが、ざっくりそれぞれのピクセルのRGB各値に変換定数を掛けてグレー画像を生成しています。
　その後、出来上がったイメージデータをtoDataURL関数でテキスト（base64）形式に変換し、FileMaker.PerformScriptWithOption関数でFileMakerスクリプト（Return）に送ります。
　ちなみに、第３引数（処理オプション）が０の場合、FileMaker.PerformScript関数（WithOptionなし）でも同義になりますが、ここでは処理オプションを省略しないほうの書き方をお薦めしておきます。

- FileMaker スクリプトを作成（return）
![スクリーンショット 2022-07-12 16.34.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/b8398380-5dcd-68c6-ac5b-3bc01ebedfc4.png)
　結果を返すためにJavaScriptから呼ばれるFileMakerスクリプトです。
　動作は単純で、受け取ったデータからデータURL形式のヘッダ（data:image/jpeg;base64,）を取り除き、データ本体を画像に変換しimage_grayフィールドに格納します。
　Base64Decode関数はファイル名をなんでもいいので指定しないと動かないので注意。
　以上で完成です。
# 動作確認
　image_colorフィールドに適当な画像をセットしてconvert_imageスクリプトを実行してみます。
　Webビューアを介して画像をグレースケールに変換することができました。
![スクリーンショット 2022-07-12 16.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728317/5b22b5c3-9b30-6b3c-f6fa-75ee3a7a668e.png)

# 終わりに
　今回はFileMaker×JavaScript実践例として、簡単な画像変換機能を作ってみました。
　製作過程を紹介するということもあり、JavaScript部分も含めフルで書いてみましたが、JavaScriptには便利なライブラリが膨大にあるので、ちょっとJavaScriptの知識があればイチから全部書かなくても、手軽にFileMakerの機能を拡張できると思います。

 この記事とほぼ同じ内容の動画も公開していますので、よろしければこちらもご覧ください。
　https://www.youtube.com/watch?v=fUZZhpyy1R0
　ご覧いただきありがとうございました。