配信一覧に好き勝手に効果を入れてみる REALITY Advent Calendar #17
REALITY Advent Calendar 17日目担当、サーバチームの落合です。
合宿に参加して開発したものを紹介していきます。
合宿参加…だと…ゴゴゴゴゴ
唐突ですが、合宿に参加したと言いましたが…
あれは嘘だ!
実は、合宿の前の週に食べた肉に当たってしまったようで、合宿の週はずっと絶不調(主にお腹が)。
弱った状態で合宿に参加しても、さらに体調を崩してもまずいですし、何より参加しても合宿のご飯もろくに食べられないでは、宿の人にも申し訳がないとか諸々考え、合宿の現地参加は断念しました。
でも、合宿開発はしたい!したい!
そんなわけで、みんなが合宿でワイワイ楽しそうに、酒を飲んだり、食事をしたり、お風呂に入ったりする報告をslackで見聞きしながら、私は腹痛を抱えて一人寂しく自宅で開発する、という合宿というより、山小屋で一人で山籠りしてるような開発形式となりました。食事も腹痛のためおかゆとかです。
…同情してもいいんですよ?
前置きはこれくらいにして。
そんな体調だったこともあり、開発にもなかなか集中できなさそうなので、何か新しいことをやろうというより、既存のREALITYのサーバ機能を使って遊べないかと思い、手をつけたのがREALITYの画像サーバの機能を使った開発でした。
REALITYの画像サーバ
REALITYには様々な画像処理を扱うための画像サーバが存在します。
機能としては、
画像サイズの変更
png/webpといった画像フォーマットの変換、出しわけ
画像アップロード
といった、画像サーバとしてはよくある機能以外にも、REALITYのギフトで使われている以下の合成機能もあります。
画像に文字を合成
絵文字を合成
名前入りタワーやフレームなど、名前が入るものでは文字&絵文字合成を行っています。絵文字については1つ1つは実際には画像なので、やっていることは絵文字の画像の合成です。
ただ、逆にギフト以外では画像や文字の合成はあまり有効に使われていません。
画像サーバの初期実装をしたのは元々自分です。
機能の実装としては golangのimage libraries を使っています。サーバの成り立ちが割と古いため、x packageの方を使っていますが、最近では image もあります。
実装としては、それほど特別なことはやらず、透過背景に文字と絵文字画像を書き込んで透過画像を作成しています。
//CreateImage キャプション画像生成
func (c Caption) CreateImage(output io.WriteCloser, text []string, w uint, h uint) error {
fontData := GetFont(c.fontType)
if fontData == nil {
return fmt.Errorf("font not exist. fontType = %s", c.fontType)
}
//透過背景作成
bgImg := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
draw.Draw(bgImg, bgImg.Bounds(), image.Transparent, image.ZP, draw.Src)
//テキスト&絵文字書き込み
if err := c.drawText(bgImg, 0, 0, text, fontData, c.fontPixelSize, c.fontCharSpacingPixel, &image.Uniform{C: c.fontColor}); err != nil {
return err
//png出力
err := png.Encode(output, bgImg)
defer output.Close()
if err != nil {
return err
}
return nil
}
テキスト書き出しのところが、ユーザー名などを合成するときはfontだけでなく絵文字を文字と合わせて合成するため、位置調整を頑張っています(ほぼ端折っているので、雰囲気だけ感じてください)。
func (c Caption) getEmojiCode(pos int, codes []rune) (isEmoji bool, emojiCodes []rune) {
var singleCodeFp, doubleCodeFp, multiCodeFp http.File
var singleEmojiCodes, doubleEmojiCodes, multiEmojiCodes []rune
var err error
singleEmojiCodes = []rune{codes[pos]}
singleCodeFp, err = OpenTwemojiPng(singleEmojiCodes)
if err == nil {
defer singleCodeFp.Close()
}
if err == nil || len(codes) > (pos+1) && emoji.IsKeycap(codes[pos+1]) {
//2文字目がkeycapの場合は1文字目該当しなくてもunicoe絵文字扱い
emojiCodes = singleEmojiCodes
} else {
return
}
isEmoji = true
if len(codes) <= pos+1 {
return
}
doubleEmojiCodes = codes[pos:(pos + 2)]
doubleCodeFp, err = OpenTwemojiPng(doubleEmojiCodes)
if err == nil {
emojiCodes = doubleEmojiCodes
defer doubleCodeFp.Close()
}
targetLen := len(codes) - pos
if targetLen > emoji.MaxEmojiMultiCodeLen {
targetLen = emoji.MaxEmojiMultiCodeLen
}
multiEmojiCodes = codes[pos:(pos + targetLen)]
emojiCharacter := emoji.GetEmojiMultiCode(multiEmojiCodes, uint(len(emojiCodes)))
return
}
合成機能自体はpackageが独立していたり汎用的に実装しているので、ギフト以外でも色々使えるようになっているのですが、あまり活用されていない。
なのでこれを使って遊んでみようと思いました。
REALITYの画像サーバを使った配信一覧芸
いきなりですが成果物です。
REALITYアプリを開くとまず最初に出てくるのは、配信の一覧画面です。
REALITYのアバターの個性がシンプルにわかって良いのですが、アバターしか写っていないこともあり、見方によってはあまり変わりばえしないように見えることもあります。
ただ、この画面に表示されているのは動いているアバター表示ではなく、画像で、画像サーバを経由して表示されていますので、画像サーバ側で実は好き勝手に弄れてしまいます。
もし、この画面の画像が一瞬にして、様々な効果がついた画像になったら楽しいのではないか…?そう思って、既存の画像合成の機能と、あらかじめ用意した透過画像(漫画の集中線、ゴゴゴゴ、などなど)をランダムに組み合わせた合成で表示してみました。
どうでしょう。カオスではありますが、なんだか賑やかで楽しげではないでしょうか?
遊びとしてタグも変えています。このタグは画像サーバとは全く関係ないのですが、これもサーバ側から動的に変更することが可能ですので、なんかよくわからんけど急に変なタブが現れた!という遊びで仕込んでいます。
やりたかったこと
時間が足らなかったのですがやりたかったこととして色々ありました。
成果だけ見ると、ただ画像を合成して、タグを変更しただけなのですが、この辺りのアプリの変更なしに、サーバのちょっとした修正だけでやれることを組み合わせられれば色々遊べると思っていました。
例えば、某有名ゲームのフェスのように、全ユーザーを2陣営に分けてしまうとかも、タブを使って2つの陣営を作って、ユーザーの配信を特定のルールで分けてしまう、とか。配信一覧に表示される配信の画像を派手に装飾すれば、配信一覧自体の見栄えは全く変えられるのでそれで遊んでみようとか。
配信者ランキングのポイントごとにタブに振り分けられて、ランクマッチのような状態を作り出すとか。
エイプリルフールみたいな時に1日限定でユーザーの全画像を髭付きにするとか。
色々賑やかしのアイデアはあって、それを試してみたかったのです。
次回の落合にご期待ください!
まとめ
時間が足らずに全く届かず、発表できるものも少なく悔しい思いをしました。合宿は計画性が大事!次こそは合宿までに仕込みまくって楽しい開発をしてみたいですね。あと、体調も整えて…皆さん、痛んだひき肉にはお気をつけください…。
最後に
明日18日目の記事は、unityチームの大黒柱であるようてんさんです!
お楽しみに。