ブラウザに表示する画像を動的に作成する

Table of Content

目的

ブラウザに表示する画像を動的に作成するというテクニックは古来より使われてきました。
たとえば、アクセスカウンターや数式の描画などに使用されています。
今回はその使用例を見るとともに、実際に自分で作成してみることにします。

実例

アクセスカウンターの例

以下のページは無料アクセスカウンターを提供しています。
http://www.rays-counter.com/

このページでアクセスカウンターを作成すると以下のようなタグを含んでいます。

http://www.rays-counter.com/d460_f6_022/5ec064f0698a5/

アクセスカウンタ

該当のURLにアクセスがあるたびに、カウンターを増やして、その内容を画像に変換して応答しています。

mimetex

http://www.forkosh.com/mimetexmanual.html
mimetexはC言語で実装されたCGIで、使用するとimgタグを使用して数式を描画することができます。

たとえば以下のようなタグを記載します。

<img src="https://needtec.sakura.ne.jp/mimetex/mimetex.cgi?\frac{-b\pm\sqrt{b^2-4ac}}{2a}">

この内容をブラウザで確認すると以下のような画像になります。

以下のページでmimetexにあたえるパラメータを試せるようにしています。
http://needtec.sakura.ne.jp/mimetex/index.php

PlantUMLのWordPressのプラグイン

WordPressのプラグインにPlantUML Renderというものがあります。
https://ja.wordpress.org/plugins/plantuml-renderer/

以前、導入方法を紹介しましたが、PlantUML Renderの仕組みも、imgタグを使用して与えたパラメータにより画像を動的に作成することで実現しています。

また、当該プラグインはPlantUMLの公式のWebサイトのURLをりようしているので、実際にWordPressをインストールしないでも、この仕組みを確認することができます。
https://plantuml.com/en/demo-javascript-synchronous

このページは以下のようなテキストエリアと画像が存在します。

テキストエリアの内容

Bob->Alice : hello

画像
UML

この画像のURLは以下になります。

http://www.plantuml.com/plantuml/img/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000

「SyfFKj2rKt3CoKnELR1Io4ZDoSa70000」という値はテキストエリアの内容によって変化します。

たとえばテキストエリアの内容を以下のように変更して送信ボタンを押してみましょう。

ボブ->アリス : こんにちは

この場合の画像とそのURLは以下のようになります。

http://www.plantuml.com/plantuml/img/0IG0s__ZWvpZWvOjFkE2ekE3gkE2kI0w8EE1a-E2a-E1g-E1eUE1hme0

「SyfFKj2rKt3CoKnELR1Io4ZDoSa70000」という値が「0IG0s__ZWvpZWvOjFkE2ekE3gkE2kI0w8EE1a-E2a-E1g-E1eUE1hme0」に変更されたことが確認できます。
この値はテキストエリアの内容を圧縮したものになっており、サーバー側はこの内容を解凍してから、その内容に応じた画像を生成しています。

AAの画像生成プログラムを作ってみる

ではこれらの先駆者の方法を利用してAAの画像生成プログラムを作ってみます。

デモサイト
https://needtec.sakura.ne.jp/aa_image/main

コード
https://github.com/mima3/aa_image

GETの受付と応答

imgタグで指定したsrcのURLにGETでリクエストされるので、その応答を作成する必要があります。
今回はPHPの軽量フレームワークである、Slim Frameworkを使用しました。

実際に画像を生成するリクエストの箇所は以下になります。
https://github.com/mima3/aa_image/blob/master/www/index.php#L89

$app->get('/image', function (Request $request, Response $response, $args) {
    // この時点でエンコードをしてくれる
    $key = $request->getQueryParams()['d'];

    $imageModel = $this->get('imageModel');
    $image = null;
    if (strlen($key) > 1024 * 10) {
        $response->getBody()->write("文字数が多すぎるため作成できません。");
        return $response->withStatus(500);
    }

    $rec = $imageModel->get($key);
    if ($rec) {
        $image = $rec->data;
    } else {
        $image = convertImage($key, $this->get('config')['FONT_PATH'], 12);
        if (strlen($image) > 1024 * 10) {
            $response->getBody()->write("画像サイズが大きすぎるため作成できません。");
            return $response->withStatus(500);
        }

        $imageModel->append($key, $image);
    }

    // 
    $response->getBody()->write($image);
    return $response
        ->withHeader('Content-Type', 'image/png')
        ->withStatus(200);
});

やっていることとしてはconvertImageという関数でクエリーパラメータからPNG画像を作成します。
その後、その内容を$responseのwriteを使用して応答を書き込み、ヘッダーを指定してます。

使いどころ

画像としてAAを作成できるため、環境によってのズレが生じません。
たとえば、QiitaやMoodleでAAを張るとズレますが、この仕組みを利用するとズレが生じなくなります。

以下は実際に作成したmoodleのプラグインになります。
https://github.com/mima3/aa_image/tree/master/moodle_plugin/filter_aa_image

懸案事項

この手法の問題としてURLが長くなってしまうことにあります。
Hypertext Transfer Protocol — HTTP/1.1 (RFC 2616)には長さの規定はないものの、サーバーならびにブラウザに上限は存在するので、何千、何万ものパラメータを渡すことはできないでしょう。

参考:

ムッシューのIT備忘録- URLの長さの上限について
https://mussyu1204.myhome.cx/wordpress/it/?p=693

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です