🦓

[Rails]mini_magickによる画像生成

2023/08/04に公開

はじめに

mini_magickを使って投稿のサムネを作っていきます。

https://github.com/minimagick/minimagick

環境

Rails 7.0.4.3
ruby 3.2.1

mini_magick

mini_magickは、Rubyプログラムで画像処理を行うためのGemです。mini_magickを使うことで、Rubyから簡単に画像のリサイズ、回転、トリミング、フィルタリングなどの操作を行うことができます。

mini_magickはImageMagickと呼ばれる画像処理ライブラリをRubyから利用するためのラッパーであり、ImageMagickのコマンドラインツールをRubyでより簡単に使えるようにしてくれます。

前提

ImageMagickがインストールされていること。
convert -versionで確認できます。

convert -version
Version: ImageMagick 7.1.1-14 Q16-HDRI x86_64 21286 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(5.0) 
Delegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg jxl lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib
Compiler: gcc (4.2)

mini_magickをインストールする

Gemfile
gem "mini_magick`"
bundle install

画像生成

テキストを含む画像を生成する時の例です。

require 'mini_magick'

# 画像のパス
input_path = 'input.jpg'

# 画像を読み込む
image = MiniMagick::Image.open(input_path)

# テキストの設定
text = "Hello,\nWorld!\nThis is a\nmultiline text."
font = 'Arial' # 使用するフォント
size = 24     # フォントサイズ
color = 'black' # テキストの色
position = 'center' # テキストの位置 (left, center, right)
offset = '0'   # テキストのオフセット位置

# テキストを画像に追加
image.combine_options do |img|
  img.gravity position # テキストの位置を設定
  img.font font
  img.pointsize size
  img.fill color
  img.draw "text 0,#{offset} '#{text}'" # テキストの内容を指定(改行を含む)
end

# 画像を保存
output_path = 'output.jpg'
image.write(output_path)

サムネカラムを追加する

投稿テーブルにサムネカラムを追加します。

bin/rails g migration AddThumbnailToPost thumbnail:string
      invoke  active_record
      create    db/migrate/20230803160727_add_thumbnail_to_post.rb
bin/rails db:migrate
== 20230803160727 AddThumbnailToPost: migrating ===============================
-- add_column(:posts, :thumbnail, :string)
   -> 0.0060s
== 20230803160727 AddThumbnailToPost: migrated (0.0060s) ======================

サムネ用メソッドを作成する

投稿を作成される際にタイトルとユーザー名を抽出しサムネを作成します。

app/models/post.rb
class Post < ApplicationRecord
...
  before_save :generate_thumbnail

  private

  def generate_thumbnail
    # 画像ファイル名
    filename = "#{id}-#{user.name.parameterize}.png"

    image = MiniMagick::Image.open(Rails.root.join('app', 'assets', 'images', 'background.png'))
    image.combine_options do |cmd|
      # タイトル
      cmd.font Rails.root.join('app', 'assets', 'fonts', 'Dot-Gothic-16-Regular.ttf')
      cmd.size "370x20"
      cmd.background "white"
      cmd.gravity 'Center'
      cmd.pointsize 32
      cmd.draw "text 0,0 '#{generate_title(title)}'"
    # ユーザー名
      cmd.font Rails.root.join('app', 'assets', 'fonts', 'Dot-Gothic-16-Regular.ttf')
      cmd.gravity 'SouthEast'
      cmd.pointsize 20
      cmd.draw "text 10,10 '#{user.name}'"
    end

    # 保存される場所
    thumb_path = Rails.root.join('public', 'thumbnails', filename)
    image.write(thumb_path)

    # DBに保存
    self.thumbnail = "/thumbnails/#{filename}"
  end
  
  def generate_title(text)
    max_characters_per_line = 8  # 一行に8文字まで
    text.to_s.scan(/.{1,#{max_characters_per_line}}/).join("\n")
  end
end

Active Storageを使う場合、イメージをblobに転換しattachメソッドを使って保存することができます。

image_blob = StringIO.new(image.to_blob)
self.image.attach(io: image_blob, filename: filename)

app/assets/images/に背景画像ファイルを用意します。
app/assets/fonts/にフォントファイルを用意します。

サムネを作成されたことを確認します。

irb(main):005:0> post = Post.last
  Post Load (0.3ms)  SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT $1  [["LIMIT", 1]]
irb(main):006:0> post.thumbnail
=> "/thumbnails/33-test_user.png"

サムネを表示させる

app/views/posts/index.html.erb
...
<% @posts.each do |post| %>
    <% if post.thumbnail.present? %>
        <%= image_tag post.thumbnail %>
    <% else %>
        <%= image_tag 'default_thumbnail.png' %>
    <% end %>
<% end %>

オプション

他にも多くのオプションがあります。

img.quality '80' # 生成されたJPEG画像のクオリティを80%に指定
img.background 'white'`, `'red'`, `'#FF0000'  # 背景色を指定
img.composite # 画像を合成 別の画像を指定の位置に重ねることができる
img.rotate "-90" # 画像を反時計回りに90度回転
img.flip # 画像を上下反転
...

オプション一覧を見る

magick -listでオプション一覧を見ることができます。

➜ magick -list style 
Any
Italic
Normal
Oblique

➜ magick -list weight
Thin
ExtraLight
UltraLight
Normal
Regular
Medium
DemiBold
SemiBold
Bold
ExtraBold
UltraBold
Heavy
Black

➜ magick -list font
...

おわりに

mini_magickは簡単の画像の作成や合成には便利ですね。

Discussion