(治安の悪くない Emoji も作れます)
作ったもの
ここで遊べます
おもしろいところ
GIF アニメのエンコードまですべて js で完結しているので、ありがちな「謎のサーバーに画像アップロードするといい感じに変換してくれる」的なサービスと違って、素性の知れたコードがクライアント側でサクサク動きます。
なにができるの?
画像を 128px x 128px に変形
画像を、 Slack にアップロードできる(現状)最大サイズの 128px x 128px に変形します。
ローカルのファイルから選ぶか、画像の URL を入力できます。アップロードするわけではないので、デカい画像でもサクサクなのがお気に入りです。
変形は
- 正方形に引き伸ばし(アス比無視)
- 正方形いっぱいに拡大して、余ったところはトリミング(アス比維持)
- 正方形に収まるように縮める(アス比維持)
から選べます。
テキストから画像生成
既存の画像を使う代わりに、テキストから画像を生成することもできます。
生成したテキスト画像も、普通の画像と同じく、引き伸ばしたり、縮小したりして正方形に収められます。
フォントは CSS っぽい感じで指定します。
アニメ
GIF アニメを作ります。節度を持ってどうぞ 😇
Slack にアップロードできるファイルサイズ制限の都合で、解像度が 1/4 (64px x 64px) になります。
キラ
絵文字がスーパーレアになります。パーティ感が出ます。
白、黒など無彩色のところはキラキラしないので、うまく使ってください。
スクロール
絵文字がスクロールします。複数並べてループできます。
ぐるぐる
絵文字が回転します。
ガタガタ
絵文字がガタガタします。飲みたくて飲みたくて震える
and more ...
プルリク待ってます✨
巨大 Emoji
画像を複数の正方形に分割して、連結すると一枚の絵になるような Emoji が作れます
巨大 Emoji にもアニメーションをつけられます (ロードのタイミングの都合で微妙に連動しないことがあります)。
技術的な話
申し訳程度に技術的にハマったところとか学んだところとか。
<img>
の crossorigin
プロパティ
img
タグは src
プロパティにヨソの URL を設定してもちゃんと読んでくれるのですが、読んだ画像を canvas
に転写してゴリゴリ変形しようとかやると、同一生成元ポリシが発動して無が転写されます。
適切なヘッダが設定されていれば、 img
に crossorigin
プロパティを設定するだけで CORS できるようなので、それを使いましたが、気付くまではハマりました。
canvas
で文字列画像を作る
canvas
で文字列画像を作るのが地味に大変というのがわかりました。
-
canvas.ctx.fillText
が複数行テキストに対応してない
文字通り、対応していないので、一行づつレンダリングする必要があります。しかもテキストの正確な高さが取れないので、二行目をどこからレンダリングしたらいいかもよくわかりません。 phina.js が canvas.ctx.measureText('あ')
(あ
の横幅) を高さとして使っていたので、今はそれを パクっ 参考にしています。
-
canvas
自体のサイズがちょっとでも足りてないと謎の物体がレンダリングされる
当初は、 canvas.ctx.measureText
でテキストの幅を、上の方法でテキストの高さを、それぞれ事前に計算して、ぴったりサイズの canvas
にレンダリングしていたのですが、謎の物体がレンダリングされて困っていました。
どうにもうまくいかなかったので、諦めてデカめの canvas
に一度レンダリングしてからトリミングしています。
JS で GIF アニメをエンコードする
技術的には一番難しいところなんですが、ここはさすがにライブラリ頼みです。
jsgif: https://github.com/antimatter15/jsgif
これが使いやすそうだったので、これを submodule にして使っています。「gh-pages
でも submodule は使えるけど、 git@...
ではなく https://...
でないとダメ」という学びがありました。
var encoder = new GIFEncoder();
encoder.setRepeat(0); // リピート回数 (0 は無限)
encoder.setFrameRate(20); // フレームレート決める
encoder.start();
for (...) {
// ... canvas で何かレンダリングする ...
encoder.addFrame(ctx);
}
encoder.finish();
こんな感じで一つ一つのフレームをレンダリングしては encoder.addFrame
していけば、謎の技術によって GIF アニメにエンコードされます。
img.src = "data:image/gif;base64," + encode64(encoder.stream().getData());
僕の作ったツールでは、できた GIF アニメをさらに data URL にエンコードして、 img
タグの src
にすることでユーザーに返しています。
まとめ
canvas
は つらい 楽しい!!
というわけで楽しい Emoji ライフを!病的なエフェクトを思いついたらぜひプルリクください!