この記事はAAをずれずに表示するために画像化することを説明する記事です。
CSSを使った方法はこちらの記事を参照してください。
AA(Shift-JIS Art)をずれずに表示するCSS設定&はみ出し対策
もし、絶対にズレないようAAを自身のWebサイトに掲載するなら画像化するという手段があります。そして、数多くの言語でテキストを画像化するライブラリが出ています。
この記事では以下の2つのライブラリを紹介します。
- text2png(node)
- gg(golang)
gg(golang)
Go言語製の画像生成ライブラリです。JavaScriptでいうCanvas的なことができ、テキスト→画像の変換も行えます。素晴らしいのはカスタムフォントを読み込む機能もあるところです。
fogleman/gg
このライブラリを使ったテキスト→画像変換のソースは以下になります。
※フォントファイルはローカルに用意しておいてください。持ってない場合は以下のサイト参照。
AAHub Fonts
package main
import (
	"bytes"
	"fmt"
	"github.com/fogleman/gg"
	"image/png"
	"strings"
)
const (
	S           = 1024
	FONT_SIZE   = 16.0
	LINE_HEIGHT = 18.0
)
func main() {
	text := `
               ____
             /      \
           / ─    ─ \
          /   (●)  (●)  \
            |      (__人__)     |
          \     `⌒´    ,/
          /     ー‐    \
	`
	lines := strings.Split(text, "\n")
	if _, err := ConvertTextToImage(lines); err != nil {
		fmt.Println(err)
	}
	fmt.Println("success")
}
func ConvertTextToImage(lines []string) ([]byte, error) {
	// 対象アスキーアートの縦横を図る
	measure := gg.NewContext(S, S)
	if err := measure.LoadFontFace("./Saitamaar.ttf", FONT_SIZE); err != nil {
		return nil, err
	}
	maxWidth := 0.0
	for _, line := range lines {
		w, _ := measure.MeasureString(line)
		if maxWidth <= w {
			maxWidth = w
		}
	}
	// 対象アスキーアートをpngに描画する
	width := int(maxWidth) + 10
	height := int(int(LINE_HEIGHT) * (len(lines) + 1))
	dc := gg.NewContext(width, height)
	if err := dc.LoadFontFace("./Saitamaar.ttf", FONT_SIZE); err != nil {
		return nil, err
	}
	dc.SetRGB(1, 1, 1)
	dc.Clear()
	dc.SetHexColor("#333333")
	for idx, line := range lines {
		i := float64(idx + 1)
		dc.DrawString(line, 10, LINE_HEIGHT*i)
	}
	dc.Clip()
	dc.SavePNG("out.png")
	img := dc.Image()
	buf := new(bytes.Buffer)
	if err := png.Encode(buf, img); err != nil {
		return nil, err
	}
	ret := buf.Bytes()
	return ret, nil
}
上記ソースコードを動かしてみると以下の画像が生成されます。良い感じですね!

ggの弱点
さて、動作も軽くて一件問題ないように見えるggですが、一点問題があります。それはHTML特殊文字に対応していないことです。(HTML特殊文字はこういうやつ♥)
そのため、特殊文字を使うAAは表示がおかしくなる可能性があります(一部フォントは大丈夫です。例えばSaitamaarは大丈夫)
なので、この問題を回避したい方は以下のtext2pngを使ってみましょう。
text2png(node)
こちらはnodeのライブラリになります。先ほどのggがCanvasっぽいことができるのに対し、こちらはnode-canvasを使っているのでほぼcanvasです。
text2png
こちらのソースコードを使ってかくと以下のような感じになります。ライブラリのおかげかggより短いですね。
const fs = require('fs');
const text2png = require('text2png');
var text = `
          ///////////////////////// ------\/////////ヽ
       ////:///////////////>  "´        ∨////////∧
      .///////////////> ´                ∨////////∧
     ///////////> ´                   ∨////////∧
     |///////,〃/                       i//////////ハ
     |////////i/            _  --――― 、--}//////////∧
     |////////|            ´    ト.     ヽ \'/////////∧
     |////////|      ..  イ        i \   ノ  ', \////////∧
     |////////|   .   ´i   i         ー|-- 斗、.    ',  \///////∧
     |////////| /    |  ハ    ',  ∧! ,ィf=ミ、   ',ー― ///////∧
     |////////|'   .、_|..斗七ヽト、   ヽ| u   {::♥::} ゞ \ ',i///////////,∧
     |////////|      |/i/,.ィf=ミ ヽト、!|   `¨¨¨´/  /\!.マニ ア//////,∧
     |////////ハ     / .ィ f:::♥ノ   | / ///// / i  |=イ/////////∧
     |////////,∧    /{ ゞ `¨´ /, j/ /// ./イ /  .|  i  i///////////
     |/////////|.ヘ  / 乂 /////      u /   |  |  i!///////////
     |/////////>j/   \          _   j/|  .| ∧!  !///////////
     |/////// ∠ィ ヘ     >_      ,ィv´  _)  / |  |/:::::∧ .|V//////////
     |//////ゝ---一 ヘ  ゝ----' u   ゝ- ´    /i .|  |:::::::::::∧!::∨/////////
     |//////////| i ∧    ',≧=-   __ .イ !ハ  |:::::::::::::_:::乂////////
     |//////////| ∧ ∧   ト{    }    i    {ーヘ !´ ̄ / アニ≧= ---
     |//////////|/::::ヘ.  ',   |从 __ノi    ',   ノ  ヘ|  / /ニニニニニニ
     |//////////|:::::::::::\{ヘ  .|-<   ゝ    r 、 -、     /  /ニニニニニニニ
     |/////////ノ==-<   ', |         r'   く      ./ニニニニニニニニ
     .ノ//>≦ニニニニニ\  }/          ` ´ \\    /ニニニニニニニニ
    .///ニニニニニニニニニ\              `´    {ニニニニニニニニニ
    .イニニニニニニニニニニニヽ                  /ニニニニニニニニニ
`;
var buf = text2png(text, {
  font: '16px aahub',
  localFontPath: fs.realpathSync("./aahub.ttf"),
  textColor: "#333333",
  backgroundColor: "#ffffff",
  localFontName: 'aahub',
});
fs.writeFileSync("./out.png", buf);
上のソースコードの実行結果は以下です。「♥」もちゃんと出力されていますね!

ソースコード
まとめ
どちらを利用するかサーバー側の要件にもよりますが、簡単にやりたいならtext2pngをお勧めします。
もし、影響のないフォントを使う、画像化に対し細かい設定もしたい(余白とか)ならggを使ってみることをお勧めします。
それでは
