
Railsで画像処理したいときはMiniMagickが使えます。MiniMagickはImageMagickのラッパーです。
リファレンスはhttps://github.com/minimagick/minimagickです。
準備 – ImageMagick
ImageMagickのインストールが必要です。
OS Xなら
$ brew install imagemagick
Ubuntuなら
$ sudo apt-get install imagemagick
終わったらバージョンを確認してみます。
$ 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のインストールはGemfileにgemを追加してインストールします。
gem 'mini_magick'
$ bundle install
使うときはrequireします。
require 'mini_magick'
画像を開く
MiniMagickでファイルを開くには、MiniMagick::Image.openを使います。こんな感じです。
image = MiniMagick::Image.open('画像ファイルへのパス')
リモートサーバー上の画像をURL経由で開く場合もopenを使います。
image = MiniMagick::Image.open('画像へのURL')
画像データを直接流し込むにはMiniMagick::Image.readを使います。
image = MiniMagick::Image.read(画像データ)
画像がないと始まらないので、Railsアプリケーションのルートに画像を置き、読み込んでみます。
image = MiniMagick::Image.open('sample.jpg')
p image
読み込んだMiniMagickオブジェクトをpで表示するとこんな感じです。@tempfileとあるのが見えるかと思いますが、openすると画像をTempfileとしてコピーして、それが編集されます。オリジナル画像には編集を加えないのが特長です。
#<MiniMagick::Image:0x007fb9c4289f80 @path="/tmp/mini_magick20160926-30947-1nwlz88.jpg", @tempfile=#<Tempfile:/tmp/mini_magick20160926-30947-1nwlz88.jpg (closed)>, @info=#<MiniMagick::Image::Info:0x007fb9c4289f58 @path="/tmp/mini_magick20160926-30947-1nwlz88.jpg", @info={}>>
画像が見つからないと次のようなエラーが発生します。
#<Errno::ENOENT: No such file or directory @ rb_sysopen - sample.jpg>
画像以外を指定すると次のようなエラーが発生します。
#<MiniMagick::Invalid: `identify /tmp/mini_magick20160926-31462-5q8fym` failed with error:
画像の情報を取得する
パスを取得するにはpathを使います。
p image.path
#=> "/tmp/mini_magick20160926-6262-1x2fdps.jpg"
いろいろな情報を取得するにはdetailsを使います。
p image.details
#=> {"Base filename"=>"mini_magick20160926-6388-1nx74jz.jpg", "Format"=>"JPEG (Joint Photographic Experts Group JFIF format)", "Class"=>"DirectClass", "Geometry"=>"1600x1062+0+0", "Resolution"=>"400x400", "Print size"=>"4x2.655", "Units"=>"PixelsPerInch", "Type"=>"TrueColor", "Endianess"=>"Undefined", "Colorspace"=>"sRGB", "Depth"=>"8-bit", "Channel depth"=>{"red"=>"8-bit", "green"=>"8-bit", "blue"=>"8-bit"}, "Channel statistics"=>{"Red"=>{"min"=>"0 (0)", "max"=>"255 (1)", "mean"=>"126.904 (0.497664)", "standard deviation"=>"46.5197 (0.18243)", "kurtosis"=>"2.84988", "skewness"=>"-0.36877"}, "Green"=>{"min"=>"3 (0.0117647)", "max"=>"255 (1)", "mean"=>"142.097 (0.557243)", "standard deviation"=>"33.7838 (0.132485)", "kurtosis"=>"2.71775", "skewness"=>"1.84254"}, "Blue"=>{"min"=>"0 (0)", "max"=>"255 (1)", "mean"=>"152.065 (0.596332)", "standard deviation"=>"43.5204 (0.170668)", "kurtosis"=>"-0.0318651", "skewness"=>"1.17011"}}, "Image statistics"=>{"Overall"=>{"min"=>"0 (0)", "max"=>"255 (1)", "mean"=>"140.355 (0.550413)", "standard deviation"=>"41.6311 (0.163259)", "kurtosis"=>"3.26784", "skewness"=>"0.529974"}}, "Rendering intent"=>"Perceptual", "Gamma"=>"0.454545", "Chromaticity"=>{"red primary"=>"(0.64,0.33)", "green primary"=>"(0.3,0.6)", "blue primary"=>"(0.15,0.06)", "white point"=>"(0.3127,0.329)"}, "Interlace"=>"None", "Background color"=>"white", "Border color"=>"srgb(223,223,223)", "Matte color"=>"grey74", "Transparent color"=>"black", "Compose"=>"Over", "Page geometry"=>"1600x1062+0+0", "Dispose"=>"Undefined", "Iterations"=>"0", "Compression"=>"JPEG", "Quality"=>"90", "Orientation"=>"Undefined", "Properties"=>{"comment"=>"Optimized by JPEGmini 3.13.0.4 0x01ee8039", "date:create"=>"2016-09-26T11:54:16+00:00", "date:modify"=>"2016-09-26T11:54:16+00:00", "jpeg:colorspace"=>"2", "jpeg:sampling-factor"=>"2x2,1x1,1x1", "signature"=>"96d0bd9e2b65b05cfc7cf78d156a5074dbfa0afd8a38d800f7518e053d714dd8"}, "Artifacts"=>{"filename"=>"/tmp/mini_magick20160926-6388-1nx74jz.jpg[0]", "verbose"=>"true"}, "Tainted"=>"False", "Filesize"=>"87.5KB", "Number pixels"=>"1.699M", "Pixels per second"=>"169.9MB", "User time"=>"0.010u", "Elapsed time"=>"0:01.010", "Version"=>"ImageMagick 6.7.7-10 2016-06-01 Q16 http://www.imagemagick.org"}
書き出す
何もしていませんが、読み込んだ画像を書き出してみます。writeで書き出せます。
image.write "resize.jpg"
次のように元の名前と同じにすると、上書きになるので注意します。
image.write "sample.jpg"
リサイズする
リサイズするには、resizeを使います。乗算記号はエックス(x)です。
image.resize "横幅x高さ"
横幅か高さのいずれかの長辺が300pxに収まるように、比率を保ったまま縮小するには次のようにします。
image.resize "300x300" image.write "wh300.jpg"
横幅が300pxに収まるように、比率を保ったまま縮小するには次のようにします。
image.resize "300" image.write "w300.jpg"
高さが300pxに収まるように、比率を保ったまま縮小するには次のようにします。
image.resize "x300" image.write "h300.jpg"
もっといろいろなリサイズ方法については公式サイトに詳しく乗っています。
http://www.imagemagick.org/script/command-line-processing.php#geometry
リサイズで画像が破損する!?
リサイズした画像を再度リサイズすると次のように画像が破損することがありました。
本来の画像。

横幅400pxへのリサイズに失敗した画像。

どうやら、次のようにリサイズ後に元のファイル名と同じ名前で保存したところ、画像情報がうまく更新されなかったようです。
image = MiniMagick::Image.open('sample.jpg')
p image.dimensions
#=> [1600, 1062]
image.resize "600"
image.write "sample.jpg"
image = MiniMagick::Image.open('sample.jpg')
p image.dimensions
#=> [1600, 1062]
2番目のdimensionsは600x398のはずなのに1600x1062と認識されていました。2番目の画像ファイル名を変更したところ、うまくいきました。
例)ダウンロードした画像をリサイズする
MiniMagick::Image.openでURLから直接画像を読み込み、横幅300pxにリサイズします。URLは架空です。
require 'mini_magick' begin uri = 'http://example.com/sample.jpg' image = MiniMagick::Image.open(uri) image.resize "300" image.write "image300.jpg" rescue => e p e end
OpenURIで画像をダウンロードしたあとに、画像データを読み込む場合は次のようにします。
require 'open-uri'
require 'mini_magick'
begin
uri = 'http://example.com/sample.jpg'
open(uri) { |io|
image = MiniMagick::Image.read(io.read)
image.resize "300"
image.write "image300.jpg"
}
rescue => e
p e
end
OpenURIで画像をダウンロードしたあとにTempfileに書き出し、Tempfileへのパス経由で画像を読み込むには次のようにします。
require 'open-uri'
require 'tempfile'
require 'mini_magick'
begin
uri = 'http://example.com/sample.jpg'
open(uri) { |io|
Tempfile.open { |t|
t.binmode
t.write io.read
t.close
image = MiniMagick::Image.open(t.path)
image.resize "300"
image.write "image300.jpg"
}
}
rescue => e
p e
end