こんにちは。エンジニアのronです。
SmartHRは、Rubykaigi 2021 Takeoutでスケジュールアプリを提供しました。
https://tech.smarthr.jp/entry/2021/11/02/204403
実はその中で、スケジュールページで設定した一言コメントがOGPに反映されるようにしていました。
これは、Twitterで自分の視聴予定をシェアしてワイワイ盛り上がってほしいという気持ちから実装したものです。
今回は、どうやって画像の生成を行っているのかを解説していきたいと思います。
画像の生成方法
Rubyで画像を生成する方法はいくつかあります。
- imagemagick
- Thinreports
- wkhtmltoimage
などが候補になりますが、今回は改行などレイアウトの簡単さから、wkhtmltoimageを使うことにしました。
実際に生成する部分のコード
https://github.com/kufu/mie/blob/main/app/controllers/plans/ogps_controller.rb
こちらが、OGPの生成を行っているコントローラーのソースコードです。
class Plans::OgpsController < ApplicationController
before_action :set_plan
def show
send_data IMGKit.new(get_html(@plan.description), quality: 20, width: 800).to_img(:png), type: 'image/png', disposition: 'inline'
end
private
def set_plan
@plan = Plan.find(params[:plan_id])
end
def get_html(body)
<<~HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
*,*::before,*::after{box-sizing:border-box}body,h1,h2,h3,h4,p,figure,blockquote,dl,dd{margin:0}ul[role="list"],ol[role="list"]{list-style:none}html:focus-within{scroll-behavior:smooth}body{min-height:100vh;text-rendering:optimizeSpeed;line-height:1.5}a:not([class]){text-decoration-skip-ink:auto}img,picture{max-width:100%;display:block}input,button,textarea,select{font:inherit}@media(prefers-reduced-motion:reduce){html:focus-within{scroll-behavior:auto}*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}}
@charset "UTF-8";
html {
font-family: 'Noto Sans CJK JP', 'Noto Color Emoji', 'Noto Emoji', sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
* {
box-sizing: border-box;
}
.ogp-frame {
width: 1200px;
height: 630px;
overflow: hidden;
background: no-repeat center url(data:image/png;#{ogp_background_image});
padding: 44px 34px 240px 64px;
line-height: 1.5;
font-size: 58px;
color: white;
word-break: break-all;
}
.ogp-body {
width: 100%;
height: 100%;
overflow-y: hidden;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
padding: 0 10px 0 0;
}
.ogp-body::-webkit-scrollbar {
display:none;
}
</style>
</head>
<body><div class="ogp-frame"><div class="ogp-body">#{ERB::Util.h(body)}</div></div></body></html>
HTML
end
def ogp_background_image
# data-url
end
end
wkhtmltoimageをrubyで扱うことができるIMGKitというGemを使用しています。使い方は非常に簡単で、
IMGKit.new
の引数にHTML文字列(と、オプション)を渡し、to_image
を呼ぶことで、画像を得ることができます。
HTML自体は、背景画像をbackground-image
にして、その上に文字を表示しているだけのシンプルなものです。
overflowやwebkit-line-clampを使用して、文字が背景からはみ出すのを防止したり、長すぎる文章の場合は4行までしか表示しないようにしたりしています。
おわりに
画像に文字列を埋め込んでレイアウトすることはかなり簡単にできるということが伝われば幸いです。
OGPに限らず、アイディア次第で様々なサービスで利用できると思います。
面白いコラ画像ジェネレーターを作ったらぜひご一報ください!