バーチャルキャストのホワイトボード用、リアルタイム画像生成方法(Rails)
カタンの盤面を例に...
完成図はこんな感じです
https://gyazo.com/d764202688cbb624d26364428e0f6df0
右下の四桁が現在時刻の分秒になっているかと思います
秒は30秒刻みです
完全な都度生成だと全員に違う画像が表示されてしまうので、同期用に幅を持たせる必要があります
今回は、合成する画像サイズや枚数が多いので30秒刻みにしています
そんな頻繁に再表示するものでもありませんから1分でもいいくらいだと思います
まず、こんな感じで素材となる画像を用意します
https://gyazo.com/717897aa3a09afe10f8d9e426018cb67
もちろん透過PNGで
それぞれのサイズなんかも、この時点で整えておきましょう
画像はいらすとやから拝借
できた画像素材はpublicディレクトリ下にこんな感じで配置しました
https://gyazo.com/96501aae9cb23a3e4512e7094954b34c
伏せてあるのは無関係なものです
public下にあるので直にファイルにもアクセスできます
プロジェクト名/assets/fonts/NotoSansCJKjp-Bold.otfに配置してます
今回はマス目の数字と、右下の生成時刻の確認用にフォントを使用しています。
肝心のコードはこんな感じで、RMagickのgemを使用しています。
code:catan_controller.rb
class CatanController < ApplicationController
require 'RMagick'
def catan_board
hitsuji = "./public/images/catan/illust/hitsuji.png"
mugi = "./public/images/catan/illust/mugi.png"
mori = "./public/images/catan/illust/mori.png"
yama = "./public/images/catan/illust/yama.png"
renga = "./public/images/catan/illust/renga.png"
oasis = "./public/images/catan/illust/oasis.png"
illust_array = hitsuji, hitsuji, hitsuji, hitsuji, mugi, mugi, mugi, mugi, mori, mori, mori, mori, yama, yama, yama, renga, renga, renga t = Time.new
time = (t.strftime("%H%M").to_i * 100) + (t.strftime("%S").to_i.div(30) * 30)
@seed1 = time + 1
@seed2 = time + 2
@seed3 = time + 3
@seed_s = time.to_s
illust_array.shuffle!(random: Random.new(@seed1))
base = Magick::ImageList.new("./public/images/catan/back2.png")
count = 18
19.times do
if count >= 16
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 445 + (18 - count) * 192, 160, Magick::OverCompositeOp)
end
if count >= 12 && count <= 15
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 350 + (15 - count) * 192, 325, Magick::OverCompositeOp)
end
if count >= 10 && count <= 11
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 255 + (11 - count) * 192, 490, Magick::OverCompositeOp)
end
if count == 9
on = Magick::ImageList.new(oasis)
base = base.composite(on, 637, 493, Magick::OverCompositeOp)
end
if count == 7 || count == 8
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 255 + (11 - count) * 192, 490, Magick::OverCompositeOp)
end
if count >= 3 && count <= 6
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 350 + (6 - count) * 192, 655, Magick::OverCompositeOp)
end
if count >= 0 && count <= 2
on = Magick::ImageList.new(illust_array0) base = base.composite(on, 445 + (2 - count) * 192, 820, Magick::OverCompositeOp)
end
if count >= 1 && count != 9
illust_array = illust_array.drop(1)
end
count = count - 1
end
on = Magick::ImageList.new("./public/images/catan/circle.png")
base = base.composite(on, 0, 0 , Magick::OverCompositeOp)
numbers = "2", "3", "3", "4", "4", "5", "5", "6", "6", "8", "8", "9", "9", "10", "10", "11", "11", "12" numbers.shuffle!(random: Random.new(@seed2))
count = 18
19.times do
geta = 0
geta = 14
end
end
if count == 18 || count == 17 || count == 16
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 483 + (18 - count) * 190 + geta, 245, numbers0) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
if numbers0 == "6." || numbers0 == "8" self.fill = '#ff0000'
else
self.fill = '#000000'
end
self.align = Magick::LeftAlign
self.stroke = 'transparent'
self.pointsize = 50
end
end
if count == 15 || count == 14 || count ==13 || count == 12
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 388 + (15 - count) * 190 + geta, 412, numbers0) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
if numbers0 == "6." || numbers0 == "8" self.fill = '#ff0000'
else
self.fill = '#000000'
end
self.align = Magick::LeftAlign
self.stroke = 'transparent'
self.pointsize = 50
end
end
if count == 10 || count == 11 || count == 7 || count == 8
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 295 + (11 - count) * 190 + geta, 577, numbers0) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
if numbers0 == "6." || numbers0 == "8" self.fill = '#ff0000'
else
self.fill = '#000000'
end
self.align = Magick::LeftAlign
self.stroke = 'transparent'
self.pointsize = 50
end
end
if count == 6 || count == 5 || count == 4 || count == 3
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 388 + (6 - count) * 190 + geta, 742, numbers0) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
if numbers0 == "6." || numbers0 == "8" self.fill = '#ff0000'
else
self.fill = '#000000'
end
self.align = Magick::LeftAlign
self.stroke = 'transparent'
self.pointsize = 50
end
end
if count == 2 || count ==1 || count == 0
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 483 + (2 - count) * 190 + geta, 907, numbers0) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
if numbers0 == "6." || numbers0 == "8" self.fill = '#ff0000'
else
self.fill = '#000000'
end
self.align = Magick::LeftAlign
self.stroke = 'transparent'
self.pointsize = 50
end
end
if count != 9
numbers = numbers.drop(1)
end
count = count - 1
end
port1 = "./public/images/catan/port/port1.png"
port2 = "./public/images/catan/port/port2.png"
port3 = "./public/images/catan/port/port3.png"
port4 = "./public/images/catan/port/port4.png"
port5 = "./public/images/catan/port/port5.png"
port6 = "./public/images/catan/port/port6.png"
ports.shuffle!(random: Random.new(@seed3))
on = Magick::ImageList.new(ports0) base = base.composite(on, 525, 910, Magick::OverCompositeOp)
on = Magick::ImageList.new(ports1) on.background_color = "none"
on = on.rotate(60)
base = base.composite(on, 142, 577, Magick::OverCompositeOp)
on = Magick::ImageList.new(ports2) on.background_color = "none"
on = on.rotate(120)
base = base.composite(on, 41, 132, Magick::OverCompositeOp)
on = Magick::ImageList.new(ports3) on.background_color = "none"
on = on.rotate(180)
base = base.composite(on, 325, 15, Magick::OverCompositeOp)
on = Magick::ImageList.new(ports4) on.background_color = "none"
on = on.rotate(240)
base = base.composite(on, 817, -42, Magick::OverCompositeOp)
on = Magick::ImageList.new(ports5) on.background_color = "none"
on = on.rotate(300)
base = base.composite(on, 918, 405, Magick::OverCompositeOp)
draw = Magick::Draw.new
draw.annotate(base, 0, 0, 1240 , 1080, @seed_s-4..-1) do self.font = './app/assets/fonts/NotoSansCJKjp-Bold.otf'
self.fill = '#585858'
self.align = Magick::LeftAlign
self.pointsize = 50
end
data = base.to_blob do
self.format = "JPG"
self.quality = 100
end
send_data(data, :disposition => "inline", :type => "image/jpeg")
end
end
ホワイトボード用にリアルタイム生成する際の肝は最下部の6行です
code:ruby
data = base.to_blob do
self.format = "JPG"
self.quality = 100
end
send_data(data, :disposition => "inline", :type => "image/jpeg")
ここですね。
今回のはまりどころとしてはRMagickのインストールとかですかね
よく憶えていないけどバージョン絡みが原因で、もたついた気がします