LoginSignup
1
2

【Rails6】ImageMagickからlibvipsに移行する

Posted at

はじめに

先日Rails6で画像処理ライブラリを変更するissueをやりました。
具体的にはImageMagickからlibvipsに移行しました。

そこで、これからlibvipsに移行したい人のために移行する方法を書いていきます。
それでは、やっていきましょう。

実際のプルリクエストです。参考にしてください

libvipsに移行する手順

先に全体像を書いておきます。
また、Rails6バージョンを想定していることに注意です。

  1. 設定ファイルの修正
  2. 既存のImageMagickに対応しているコードを修正する
  3. (必要なら)Dockerfile, CI設定ファイルの修正もする

libvipsに移行するだけなら、簡単なのですがアプリによって2の修正箇所が違ったりするので大変です。
以下で詳しく書いていきます

1. 設定ファイルの修正

config/application.rbファイルに1行加えるだけで、ライブラリ自体は変更できてしまいます。

config/application.rb
# frozen_string_literal: true
...

module Myapp
  class Application < Rails::Application
  ...
    # 下記1行を追加する
    config.active_storage.variant_processor = :vips
  end
end

これだけです、簡単ですね。
ただ、ここから気をつけないとエラーを起こしてしまうので2は特に要チェックです。

2. 既存のImageMagickに対応しているコードを修正する

ここから、既存のコードをlibvipsに対応させていきます。
主に見るのはvariantメソッドについてです。

下記のように画像をvariantで加工している箇所はないでしょうか?

修正対象のコード
avatar.variant(resize: '88x88>').processed.url

主にその箇所を修正していきます。
もっと具体的にいうとresize: '88x88>'という部分を修正します。

Railsガイドに書いてある下記の表が、参考になります。

パラメータ 説明
resize_to_limit resize_to_limit: [100, 100] 元の縦横比を維持したまま、指定の寸法に収まるように画像を縮小します。指定の寸法より大きい場合のみ、画像のサイズを変更します。
resize_to_fit resize_to_fit: [100, 100] 元の縦横比を維持したまま、指定の寸法に収まるように画像をリサイズします。指定の寸法より大きい場合は縮小し、小さい場合は拡大します。
resize_to_fill resize_to_fill: [100, 100] 元のアスペクト比を維持したまま、指定の寸法に収まるように画像をリサイズします。必要な場合は、大きい方の寸法で画像を切り取ります。
resize_and_pad resize_and_pad: [100, 100] 元の縦横比を維持したまま、指定の寸法に収まるように画像をリサイズします。必要に応じて、元画像にアルファチャンネルがある場合は透明色で、ない場合は黒で残りの領域を塗ります。
crop crop: [20, 50, 300, 300] 画像から領域を抽出します。最初の2つの引数は、抽出する領域の左端と上端、最後の2つの引数は、抽出する領域の幅と高さです。
rotate rotate: 90 画像を指定の角度だけ回転します。

例えば、resize_to_limitを使って先ほどの修正対象のコードを修正したら下記のようになります。

修正後のイメージ
avatar.variant(resize_to_limit: [88, 88]).processed.url

厳密には違うかもですが、あくまでイメージですので許してください。

注意: ImageMagick依存のgemもチェックしよう

上記の修正を終えた僕は「なんだ〜〜簡単じゃん!!」と油断していました。

しかし、本番環境にリリースされた時バグを発生させてしまったのです。
(しかも、結構クリティカルなバグ...)

なぜバグが起こったのでしょうか?
それはMiniMagickというgemを使って画像処理をしていた箇所でエラーを起こしていました。

どうやら、MiniMagickを使うにはImageMagickが必要だったそう...
なので、下記のようなコードを見つけたらlibvipsに対応した書き方に修正しましょう。

修正対象のコード2
MiniMagick::Image.read()

結局チームリーダーが対処してくださいました↓
ありがとうございました。

(必要なら)Dockerfile, CI設定ファイルの修正もする

開発しているアプリにもよりますが、Dockerfile, CI設定のファイルでもlibvipsをインストールしないとエラーになります。
具体的には、下記のようなエラーになりました。

エラーログ
rails aborted!
LoadError: Could not open library 'vips.so.42': vips.so.42: cannot open shared object file: No such file or directory.
Could not open library 'libvips.so.42': libvips.so.42: cannot open shared object file: No such file or directory.
Searched in <system library path>, /usr/lib, /usr/local/lib, /opt/local/lib
/home/circleci/project/vendor/bundle/ruby/3.1.0/gems/ffi-1.16.3/lib/ffi/dynamic_library.rb:65:in `load_library'
/home/circleci/project/vendor/bundle/ruby/3.1.0/gems/ffi-1.16.3/lib/ffi/library.rb:95:in `block in ffi_lib'
/home/circleci/project/vendor/bundle/ruby/3.1.0/gems/ffi-1.16.3/lib/ffi/library.rb:94:in `map'
/home/circleci/project/vendor/bundle/ruby/3.1.0/gems/ffi-1.16.3/lib/ffi/library.rb:94:in `ffi_lib'
/home/circleci/project/vendor/bundle/ruby/3.1.0/gems/ruby-vips-2.2.0/lib/vips.rb:573:in `<module:Vips>'
...

libvipsを開けないよ!みたいなエラーなので、インストールしていきましょう。
ただ、設定ファイルは各自の開発しているアプリにより違いそうなので、カスタマイズしてください。

Dockerfileの修正

imagemagickの部分をlibvipsをインストールするように置き換えています。

.devcontainer/Dockerfile
# Install OS packages
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
    # 修正前
    && apt-get -y install --no-install-recommends imagemagick pngcrush optipng gsfonts

    # 修正後
    && apt-get -y install --no-install-recommends libvips42 libvips-dev pngcrush optipng gsfonts
Dockerfile
# ImageMagick(修正前)
RUN apk add --no-cache imagemagick imagemagick-heic imagemagick-jpeg imagemagick-pdf imagemagick-svg imagemagick-webp bash pngcrush optipng=0.7.8-r0 ghostscript-fonts

# libvips(修正後)
RUN apk add --no-cache vips-dev orc-dev bash pngcrush optipng=0.7.8-r0 ghostscript-fonts

CI設定ファイル

こちらは単純にapt-getでパッケージをインストールするだけになります。

.circleci/config.yml
...
  # (すでに同様のcommandがあれば不要)パッケージの更新
  - run:
    name: Update package list
    command: sudo apt-get update
  # libvipsをインストールする
  - run:
    name: Install libvips
    command: sudo apt-get install -y libvips

ひとまずこれでOKだと思います。

HEIC形式に注意する

上記の方法で、またもや本番エラーを起こしてしまいました。
HEIC形式に対応していなかったのです。

なので、先ほどのDockerfileを修正しましょう。

Dockerfile
# vips-heifを追加する
RUN apk add --no-cache vips-dev vips-heif orc-dev bash pngcrush optipng=0.7.8-r0 ghostscript-fonts

こちらのリーダーに対処していただきました。何度もすいません...

また、こちらのコメントも参考になりました↓
(僕のインストール方法がそもそもでよくなかった?)

終わりに

以上で完了です!意外とスッといけたと思ったら本番でエラーばかりでした...
申し訳ございません。フォローありがとうございました

この記事を読んで少しでも事故が減ればいいなと思っています。

いいねなどもしていただけると嬉しいです
それでは!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2