RailsでCarrierWaveを使い、画像をリサイズする方法です。OSはUbuntu Server 16.04です。
概要
リサイズにはImagemagick
と、MiniMagick
かRMagick
が必要です。公式ではImagemagick
とMiniMagick
の組み合わせを推奨しているようです。この記事でも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 uploader
でuploader
を作成します。CarrierWaveの設定ファイルみたいなものです。
rails generate uploader Image
#create app/uploaders/image_uploader.rb
生成されたapp/uploaders/image_uploader.rb
を開いて、次のような感じにします。include
でMiniMagick
を読み込みます。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を行ったときに、画像が壊れることがありました。下のように灰色の部分が生じました。
原因不明なので、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