定食屋おろポン

おろしポン酢と青ネギはかけ放題です

RMagickを使ってアプリ用のサンプル画像を量産しよう

やりたいこと

あなたはiOSアプリを開発しているとします。

一週間後に、デザイナーからimage1.pngからimage100.pngまでの100枚の画像リソースが届きます。あなたはこの画像をアプリに組み込んで表示しなければいけません。

しかし、デザインが届くのを待ってから開発に着手するのでは開発が遅れてしまいます。お客さんが激おこぷんぷん丸になります。

仕方ないので、とりあえずは仮の画像を当てて作業することにします。

Placehold.it - Quick and simple image placeholders などを利用して仮の画像を作ってもいいのですが、それでは..

image15.pngを入れるべき場所にimage37.pngを入れちまってた!!やべえ!!」

っていうケアレスミスを開発時点で気づくことができません。

それでは、画像自体にidを記載してしまいましょう。 image1.pngには「1」って書いて、image57.pngには「57」って書いて、image100.pngには「100」って書けばいいんです。

...でも、どうやって?手作業??100枚も???

僕は耐えられません。目の前の箱に働いてもらいましょう。

※ 状況設定はフィクションです。スマホアプリ開発に限らず、Webアプリ開発でもなんでも使えます。

準備する

Homebrewimagemagickを入れる。

% brew install imagemagick

bundlerrmagickを入れる。別にgem install rmagickでもいい。

% bundle init
% echo gem \"rmagick\" >> Gemfile 
% bundle install
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Installing rmagick 2.13.2
Using bundler 1.6.2
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.

Sample用にoctcat.pngを仕入れてくる。octcatかわいい。

% curl -o octcat.png https://octodex.github.com/images/original.png

f:id:oropon:20140514024820p:plain

情報収集

準備は万端。ドキュメントから必要な情報を仕入れる。

http://www.imagemagick.org/RMagick/doc/usage#drawing_on.html

The annotate method draws text on an image.

「annotateメソッドは画像にテキストを描画します。」

面倒くさいので英語はすっ飛ばしてサンプルコードだけ見る。

#! /usr/local/bin/ruby -w
require 'RMagick'

# Demonstrate the annotate method

Text = 'RMagick'

granite = Magick::ImageList.new('granite:')
canvas = Magick::ImageList.new
canvas.new_image(300, 100, Magick::TextureFill.new(granite))

text = Magick::Draw.new
text.font_family = 'helvetica'
text.pointsize = 52
text.gravity = Magick::CenterGravity

text.annotate(canvas, 0,0,2,2, Text) {
   self.fill = 'gray83'
}

text.annotate(canvas, 0,0,-1.5,-1.5, Text) {
   self.fill = 'gray40'
}

text.annotate(canvas, 0,0,0,0, Text) {
   self.fill = 'darkred'
}

canvas.write('rubyname.gif')
exit

ImageList.newでキャンバスを初期化

Draw.newで描画オブジェクトを初期化

描画オブジェクトにプロパティを設定し、annotateメソッドで描画を行う。

annotateメソッドに渡すブロック内でfillを指定することで、文字の塗りつぶしを行う。

write(fpath)でファイルに書き込む。

このコードではテキストの描画位置と色を変えて複数回描画することで、凹凸(ベベルとエンボス)を表現している。

fmfm。なんとなく理解したらおk。次に進む。

書いてみる

サンプルコードを元に細かい修正を加える。 細かいところはコメントに書いた。

require 'RMagick'
include Magick # 面倒くさいのでinclude

Text = "Hello, My name is Octcat!"

img = ImageList.new 'octcat.png' # ImageList.new file_path で画像読み込み

text = Draw.new # 描画オブジェクトを初期化
text.font = '/System/Library/Fonts/Avenir Next.ttc' # フォントはフォント名だけではなく絶対パスで指定
text.pointsize = 52
text.gravity = CenterGravity # 上下中央寄せしてくれるみたい

text.annotate(img, 0,0,0,0, Text) {
   self.fill = 'gray' # カラーコードか色名を入れる
}

img.write('octcat_greeting.png') # 書き出し

f:id:oropon:20140514024849p:plain

ね、簡単でしょう?

注意点として、少なくとも手元のMacでは、fontにフォントの絶対パスを指定する必要があった。 パスがわからない場合は、Font Book.appでフォントを検索して、右クリックからShow in Finderしてファイルパスを調べればおk。

量産してみる

文字を縁取りし、量産してみる。

annotate fname

f:id:oropon:20140514032150p:plain

f:id:oropon:20140514032100p:plain

注意するところは、Line29のimg.copycopyメソッドを呼んでdeep copyを行わないと、同じ画像に対して何度もテキストを上書きすることになってごちゃごちゃになる。

iOS用にRetina用と非Retina用の画像を量産するならこんな感じで行ける。(てきとう)

require 'RMagick'
include Magick

id_min = 0
id_max = 100

def annotate_id img, id, thumb=false
  fname = "Octcat_%03d#{'@2x' unless thumb}.png" % id
  scale = thumb ? 0.5 : 1.0
  img = img.scale(scale)

  text = Draw.new
  text.font = '/System/Library/Fonts/Avenir Next.ttc'
  text.pointsize = (1500 / fname.length) * scale
  text.gravity = CenterGravity

  text.annotate(img, 0,0,0,0, fname) {
     # 画像の色にかかわらず文字が読めるように縁取りする
     self.stroke_width = 3 * scale
     self.stroke = 'white'

     self.fill = 'gray30'
  }

  img.write(fname)
end

img = ImageList.new 'octcat.png'

id_min.upto(id_max) do |i|
  annotate_id img.copy, i
  annotate_id img.copy, i, true
end

f:id:oropon:20140514034738p:plain

f:id:oropon:20140514034742p:plain

まとめ

ImageMagickを使ったことなくて焦ったけど、意外と簡単に使えた。みんなも使おう。

目の前の箱のマスターとなってビシバシ働いてもらおう。