Rails CarrierWaveで画像をリサイズする

RailsでCarrierWaveを使い、画像をリサイズする方法です。OSはUbuntu Server 16.04です。

概要

リサイズにはImagemagickと、MiniMagickRMagickが必要です。公式ではImagemagickMiniMagickの組み合わせを推奨しているようです。この記事でもMiniMagickを使います。

Imagemagickのインストール

ImagemagickをUbuntuへインストールします。

$ sudo apt-get install imagemagick

convertコマンドが使えるようになっているので、バージョンを表示してみます。

$ convert -version
Version: ImageMagick 6.7.7-10 2016-06-01 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP    

MiniMagickのインストール

MiniMagickはgemをGemfileに追加します。

gem 'mini_magick'
$ bundle install

Vagrantを使っていて、実行時にNoMethodErrorとエラーが出る場合は、Vagrantを再起動すると直るかもしれません。

Uploaderの作成

rails generate uploaderuploaderを作成します。CarrierWaveの設定ファイルみたいなものです。

rails generate uploader Image
#create  app/uploaders/image_uploader.rb

生成されたapp/uploaders/image_uploader.rbを開いて、次のような感じにします。includeMiniMagickを読み込みます。version :thumbでは、横幅300pxの画像を生成しています。

class ImageUploader < CarrierWave::Uploader::Base
 include CarrierWave::MiniMagick

 storage :file

 def store_dir
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
 end

 version :thumb do
  process resize_to_fit: [300, nil]
 end
end

Uploaderをマウントする

任意のモデルにstring型のカラムを用意して、Uploaderをマウントします。

例としてImageモデルにdataカラムを用意します。

create_table :images do |t|
 t.string :data # 画像データ(CarrierWave管理)
end

モデル定義では次のようにマウントを指示します。

class Image < ApplicationRecord
 mount_uploader :data, ImageUploader
end

使用する

リモートサーバーにある画像を取得し、CarrierWaveで保存してみます。

require 'mini_magick'
begin
 uri = 'http://example.com/foo.jpg'
 img = MiniMagick::Image.open(uri)
 obj = Image.new
 obj.data = img
 obj.save!
rescue => e
 p e
end

public/uploads/imageフォルダにオリジナル画像とversion :thumbでリサイズした画像ができたかと思います。

オリジナル画像のサイズを変更する

オリジナル画像を縮小してから保存したい場合は、Uploaderにversion指定無しでprocessを指定します。

class ImageUploader < CarrierWave::Uploader::Base
 略

 # オリジナル画像を横幅600pxに制限して保存する。
 process resize_to_fit: [600, nil]

 # 横幅300pxのバージョンも作成する。
 version :thumb do
  process resize_to_fit: [300, nil]
 end
end

オリジナル画像のサイズを変更すると画像が壊れる!?

上記のオリジナル画像に対してprocessを行ったときに、画像が壊れることがありました。下のように灰色の部分が生じました。

thumb_c79619e7-56dc-4934-91a2-e61876b6b7f4

原因不明なので、Uploaderでオリジナル画像のリサイズを行わずに、MiniMagickでリサイズ済みの画像をCarrierWaveに渡すようにしました。

img.resize "600"の箇所がオリジナル画像のリサイズです。

require 'mini_magick'
begin
 uri = 'http://example.com/foo.jpg'
 img = MiniMagick::Image.open(uri)
 img.resize "600"

 obj = Image.new
 obj.data = img
 obj.save!

rescue => e
 p e
end