はじめに
Qiitaやはてなブログの画像のない記事をシェアするときに、タイトルが入ったOGP画像が出るようになったのを見ていて、ずっと真似したいと思ってました。
マシュマロでコメントが画像になっていて、自分の返事のツイートにつけられているのを見て、うまいなぁ、と感激し、自分もマネしてみたいと思い、作ってみました。
サンプルアプリケーション
サンプルアプリケーションは、ユーザが好きな文章を投稿できる、シンプルなものです。(基本的にはrails g scaffold post body:string
です。)
これに、投稿をシェアするツイートに画像をつけて上げるために、いろいろしています。
ソース
https://github.com/ken1flan/minimagick_ogp
heroku
https://minimagick-ogp.herokuapp.com/posts
詳細
ツイートボタン
twitterで画像を使った情報をシェアするときに2つ方法があると思います。
- 画像を添付してツイート
- リンクのOGPによるプレビュー
先の画像を添付する形が、普通にツイートするときには簡単だと思って調べたのですが、よくあるツイートボタンはただの、簡単に画像を添付することができなそうだったので、OGPを使った方法にすることにしました。
<!-- 省略 -->
<p>
<%= render 'common/twitter_share_button', url: post_url(@post), message: 'ありがとうございます!' %>
</p>
<!-- 省略 -->
<a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-text="<%= message %>" data-url="<%= url %>" data-show-count="false">Tweet</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
ツイッターカードと画像の縦横比
シェアしてもらうページのメタタグでtwitter:card
を設定しておくとプレビューの形を選べます。
これによって、OGPの画像の縦横比を変えたほうがよいです。せっかくテキストを埋め込んだ画像を合成しても、見切れてしまっては伝わらないですから…。
ここでは画像が大きめに出る summary_large_image
を設定し、合成する画像のサイズは640x315
にしました。
<%
set_meta_tags title: "post##{@post.id}", og: { title: "post##{@post.id}", description: @post.body, image: "#{request.base_url}/#{@post.image_path}" }, twitter: { card: 'summary_large_image' }
%>
:
(省略)
フォント
画像にテキストを書き込むので、そのときのフォントが必要になります。
必然的に配布してしまうことになるので、画像に書き込んだものを配布しても大丈夫なライセンスで提供されているものを探さなくてはなりません。
サンプルでは、IPAexフォントを使っています。
これを app/assets/fonts
に配置しています。
画像合成用のクラス
投稿Post
に対して、画像を合成するものなので、Post::Image
という名前にしました。
class Post::Image
# (省略)
attr_reader :post
def initialize(post)
@post = post
end
# (省略)
end
これをPost
からimage_path
とすると合成された画像のパスを得られるようにしています。
class Post < ApplicationRecord
delegate :path, to: :image, prefix: true
def image
@image ||= Post::Image.new(self)
end
end
テキストの整形
MiniMagickによるテキストの描画は、指定位置で改行するなどの機能がないので、自分で整形する必要があります。
画像のサイズは有限なので、表示できる一行の文字数と、行数を決め、それに合わせてテキストを整形していきます。
class Post::Image
# (省略)
MAX_ROWS = 5
COLS = 20
ROWS = 10
OMMIT_MESSAGE = '…(省略させてください。)'
# (省略)
def formated_body
lines = post.body.lines.map { |line| line.scan(/.{1,#{COLS}}/) }.flatten
lines = lines[0, MAX_ROWS - 1].push(OMMIT_MESSAGE) if lines.size > MAX_ROWS
lines.join('\n')
end
# (省略)
end
合成
画像を開いて、整形したテキストを描画しています。
class Post::Image
FRAME_IMAGE_PATH = Rails.root.join('app/assets/images/flame.png')
FONT_PATH = Rails.root.join('app/assets/fonts/ipaexg00401/ipaexg.ttf')
FONT_SIZE = 25
INTERLINE_SPACING = (FONT_SIZE * 0.5).round
COLOR_CODE = '#252828'
START_X = 65
START_Y = 60
# (省略)
def image
image = MiniMagick::Image.open(FRAME_IMAGE_PATH) # 枠の画像を開き
image.combine_options do |c|
c.gravity 'northwest' # 左上から
c.pointsize FONT_SIZE # 指定のフォントサイズで
c.font FONT_PATH # 指定のフォントで
c.interline_spacing INTERLINE_SPACING # 指定の行間のスペースで
c.stroke COLOR_CODE # 指定の色で
c.annotate "+#{START_X}+#{START_Y},0", formated_body # 整形したテキストを指定位置から描画します
end
end
# (省略)
end
ツイートのプレビューのリセット
作った画像が気に入らないときもあると思います。ですが、最適化の関係と思われますが、プレビューがキャッシュされてしまって、変更しても反映されないことがあります。そのときにはカードバリデータでプレビューを見ると、取り直してくれます。
やってみて
OGPを使った場合だと、シェアしてもらうコンテンツにそもそもURLがないとダメなのがネック…。
普段からコンテンツをキレイに分割するようにしておきたいです。