iOS App Icon セットのおすすめの作り方

2019/12/12 新規 2022/09/13 更新 山田 泰司 <taiji@aihara.co.jp>

iOS App Icon セット

iPhone アプリのアイコンはデバイスや解像度の種類に合わせて、多くのサイズの画像を登録する必要があります。2019年の執筆現在、19種類もの画像ファイルを必要とします。

$ ls -1
PlaceN-20@2x.png
PlaceN-20@3x.png
PlaceN-29.png
PlaceN-29@2x.png
PlaceN-29@3x.png
PlaceN-40@2x.png
PlaceN-40@3x.png
PlaceN-60@2x.png
PlaceN-60@3x.png
PlaceN-Small-20.png
PlaceN-Small-20@2x.png
PlaceN-Small-29.png
PlaceN-Small-29@2x.png
PlaceN-Small-40.png
PlaceN-Small-40@2x.png
PlaceN-76.png
PlaceN-76@2x.png
PlaceN-83.5@2x.png
PlaceN-1024.jpg

ここで、PlaceN はアプリのプロダクト名と思ってください、その次、ハイフンに続く文字列がサイズ、及び、アットマークに続く解像度に伴う倍率、そして、拡張子となっています。一つの JPEG 形式を除き他は PNG 形式です。JPEG 形式は AppStore 用アイコンで、サイズが特別大きいので非可逆圧縮形式が推奨されています。用途が異なるだけで実質的にサイズが等しい画像ファイルがいくつもありますが、ここでは同じ画像を自動的に生成するものとします。適宜、手作業で別の図柄を用意してもよろしいでしょう。

SVG エディタ

ここで、おすすめの元画像ファイル形式を決めます。それは SVG 形式です。スケーラブルベクターグラフィックス (SVG: Scalable Vector Graphics) の名前の通り、拡大縮小しても画質が劣化しませんので、今後の解像度の増加に対応が容易です。

手っ取り早くオンラインで画像を作成したいという方にいくつかフリーのオンライン SVG エディタを紹介します。他にも探せば色々ありますので、自分が使いやすいものを選べばよいでしょう。

Inkscape を macOS にインストールするには、2019年の執筆現在、1.0beta2 版の dmg ファイルをダウンロードするか、MacPorts もしくは Homebrew 経由でインストールするか、などです。

Homebrew 利用上の注意

ところで、MacPorts と Homebrew の両方をインストールしている人が稀に見受けられますが「混ぜるな危険」であることを知らない人が多いようです。これは Homebrew に非があって、ビルドに用いる configure スクリプトは /usr/local に依存するように作られているわけですから、そのままの Homebrew が存在すると MacPorts 他が Homebrew に徐々に依存し始めてしまい、提供者が意図しないビルドや障害が生じ得ます。そこで、Homebrew を /usr/local ではない場所「/Users/Homebrew」にインストールするためのシェルスクリプトを以下に示しますので、Homebrew を使う人は参考にしてください。

#!/bin/ksh
prefix="${prefix:-/Users/Homebrew}"
(cd "$(dirname "$prefix")" && sudo mkdir "$(basename "$prefix")" && sudo chown ${LOGNAME}:staff "$(basename "$prefix")" &&
     curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$(basename "$prefix")" &&
     sudo chown -R "${LOGNAME}:staff" "$(basename "$prefix")" &&
     (cd "$(basename "$prefix")" &&
	  sudo mkdir -p etc include lib opt sbin share var/homebrew/linked Cellar &&
	  sudo chown -R "${LOGNAME}:staff" etc include lib opt sbin share var Cellar
      )
) &&
"$prefix"/bin/brew doctor
echo $ sudo xcode-select --install
echo $ "$prefix"/bin/brew tap homebrew/cask
echo $ "$prefix"/bin/brew update

echo で表示されたコマンドは手動で実行しておいてください。

Homebrew Cask は App を /Applications へ Homebrew 経由でインストールするための拡張です。MacPorts や Homebrew の使い方、Inkscape の使い方は他に譲ります。

SVG 画像の作成上の注意

さて、肝心のアイコン画像の作成に掛かります。非可逆圧縮の JPEG 形式は論外として、PNG 形式でもよいのですが、前提として 1024x1024 ピクセルの画像をアイコン画像として、SVG 形式で用意してください。

重要な注意事項としては、1024x1024 ギリギリまで描かずに、少なくとも1ドット余白を残すようにすることです。なぜかと言うと、画像の縮小時にアンチエイリアスを用いて美麗に見えるようにするのですが、縁のピクセルにはアンチエイリアスを上手く効かすことが出来ないからです。

PlaceN.svgeMojiCalc.svg

SVG のレンダラーとしてのヘッドレスブラウザ

SVG のレンダリングを何に任せれば最も高性能かを考えます。普通に考えれば Inkscape 本体に PNG 形式で出力をさせればよいと考えがちですが、実はフォントがらみであまり性能がよろしくない場合が多々あります。例えば、最新の Unicode 規格に対応していないなどです。これでは SVG の表現力のすべてを発揮できません。

SVG のレンダリングに最も適しているのは「ブラウザ」です。しかし、自動化したいわけですからブラウザを「いつものように」使うわけではなくヘッドレスモードでコマンドラインで使用します。ここでは Firefox と Google Chrome を前提にして進めます。以下「$*」はベースネームであるプロダクト名を指しています。

Chrome の場合、以下のように SVG から PNG が生成できます。

$ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --lang=ja --headless --window-size=1024,1024 --screenshot="$*-1024.png" "$*.svg"

ここで Chrome では、なぜか絵文字が表示されないというフォント処理機構上の問題があります。無視できるならこれで良いのですが(2022/09/10追記) 一部のグリフが化けてしまうというフォント処理機構上の問題が多少あります。念の為、同様の処理を Firefox でも出来るようにしましょう (但し、一筋縄では行かないのでした)。

$ /Applications/Firefox.app/Contents/MacOS/firefox --headless --profile .profile --window-size 1024,1024 --screenshot "$*-1024.png" "$*.svg"

しかしこんな簡単なことが Firefox では不可能なのです。ローカルファイル "$*.svg" を受理してくれません (http://〜 なら受理されますが、それだとウェブサーバ上にファイルを置かざるを得ず、非常に面倒です)。では URL なら受理してくれるかと、絶対パスで以下のようにしてみます。

$ /Applications/Firefox.app/Contents/MacOS/firefox --headless --profile .profile --window-size 1024,1024 --screenshot "$*-1024.png" "file://$PWD/$*.svg"

ここで環境変数 PWD にはカレントディレクトリのパスが入っています。これでも受理してくれません。苦肉の策で、データ URL を用います。

$ /Applications/Firefox.app/Contents/MacOS/firefox --headless --profile .profile --window-size 1024,1024 --screenshot "$*-1024.png" "data:image/svg+xml;base64,$(base64 -b 0 "$*.svg")"

base64(1) コマンドでデータ URL のデータをソースファイルから生成しています。これでめでたく、Firefox でも SVG のレンダリングが可能となりました。本当にこれを見つけるのに苦労しましたが、将来的にはこうした問題は解決されると思います。

その他のヘッドレスブラウザ

かつて WebKit ベースのヘッドレスブラウザ PhantomJS がありましたが、開発が凍結されました。とは言え、2019年の執筆現在、試してみても十分に使用することが出来ています。また、Firefox を利用する SlimerJS がありますが、古い Firefox 56.0.2 を必要とし、少々品質が劣るようです。昨今は Selenium WebDriver などを使って柔軟かつ堅牢に自動化するのが主流のようですが、ここではいささか大げさになるのでブラウザ本来のヘッドレスモードを紹介しました。

さまざまなサイズの画像を自動生成

さて、これで十分な解像度の PNG 画像が得られたので、そこから画像を縮小して各種アイコンファイルを生成しましょう。幸い、macOS には標準で sips(1) という画像処理コマンドがありますので、それを利用します。一例だけ示します。

$ sips -Z 180 "$*-1024.png" --out "$*-60@3x.png"
by_firefox/for_ios/PlaceN-60@3x.pngby_firefox/for_ios/eMojiCalc-60@3x.png

さて、ここまでコマンドラインでの処理方法を説明していますが、結論から言うと、配布物の make-icons-*.zipmakefile にて自動化されているので、それをそのまま使えば事足ります。

$ make
$ make backup
$ make clean
これで by_firefox にすべてのアイコンセットが生成されます。Chrome の方が調子が良いなら
$ make headless_browser=chrome all backup clean

とすれば by_chrome にすべてアイコンセットが生成されます。以下の例のように、2019年の執筆現在、Chrome では絵文字が表示されません。

by_chrome/for_ios/PlaceN-60@3x.pngby_chrome/for_ios/eMojiCalc-60@3x.png

Xcode プロジェクトへのアイコンセットの登録

プロジェクト毎で Assets の AppIcon に生成されたアイコンファイルをすべて選んでドラッグ&ドロップして下さい。すると、いくつかは警告が出て枠に入れてくれませんが、手動で一つずつ警告で枠外のアイコンを適切に配置すれば登録完了です。

配布物

参考文献

本文中の外部リンクを参考にして下さい。

附録 GNU make の makefile

配布物に入っている、このアイコンセットを SVG ファイルから生成するための GNU make 用の makefile を解説付きで紹介します。(2022/09/10追記) macOS 非対応版のままですが、解説が煩雑になるのでそのままにしておきます。

#
# makefile - create icons of various sizes
#
# Copyright (C) 2019 Taiji Yamada <taiji@aihara.co.jp>
#
# usage:
#
# $ make clean all backup
# $ make headless_browser=chrome clean all backup
#
SVGS=\			# 変数 SVGS の定義−ソースファイル群
PlaceN.svg	\
eMojiCalc.svg	\

SUFS=\			# 変数 SUFS の定義−生成されるターゲットファイル名に付加されるサフィックス群
-20@2x.png	\
-20@3x.png	\
-29.png	\
-29@2x.png	\
-29@3x.png	\
-40@2x.png	\
-40@3x.png	\
-60@2x.png	\
-60@3x.png	\
-Small-20.png	\
-Small-20@2x.png	\
-Small-29.png	\
-Small-29@2x.png	\
-Small-40.png	\
-Small-40@2x.png	\
-76.png	\
-76@2x.png	\
-83.5@2x.png	\
-1024.jpg	\

IMGS=\			# 変数 IMGS の定義−生成されるターゲットファイル群、foreach 関数により PlaceN-20@2x.png PlaceN-20@3x.png ... eMojiCalc-20@2x.png eMojiCalc-20@3x.png ... と変数展開される。
$(foreach svg, $(SVGS),$(foreach suf,$(SUFS),$(svg:%.svg=%$(suf))))	\

all:: $(IMGS)		# 最初に現れるターゲット行が規定のターゲット:変数 IMGS を展開したもの

#headless_browser=chrome	# 条件分岐のための変数 headless_browser の定義
headless_browser=firefox	# これらのどちらかを選ぶ

ifeq ($(headless_browser),chrome)

chrome="$(shell find /Applications -maxdepth 2 -name 'Google Chrome.app' -print -quit)/Contents/MacOS/Google Chrome"
chrome_headless_flags=--lang=ja --headless --window-size=1024,1024

%-1024.png: %.svg	# ターゲットファイル名のパターン:ソースファイル名のパターンーコロンを挟んで左が「$@」右が「$<」
	$(chrome) $(chrome_headless_flags) --screenshot="$@" "$<"	# 行頭がタブ:ターゲットを生成するためのシェルのコマンドを記述
#
# これは以下のように変数展開されて実行される
#
# "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --lang=ja --headless --window-size=1024,1024 --screenshot="$*-1024.png" "$*.svg"
#
endif
ifeq ($(headless_browser),firefox)

firefox="$(shell find /Applications -maxdepth 2 -name Firefox.app -print -quit)/Contents/MacOS/firefox"
firefox_headless_flags=--headless --profile .profile --window-size 1024,1024

%-1024.png: %.svg
	$(firefox) $(firefox_headless_flags) --screenshot "$@" "data:image/svg+xml;base64,$$(base64 -b 0 "$<")"	# 行頭がタブ:ターゲットを生成するためのシェルのコマンドを記述
#
# これは以下のように変数展開されて実行される(タブ行でシェルの「$」を使いたいとき「$$」とすること。さもなくばすべての「$」は makefile の変数展開である)
#
# /Applications/Firefox.app/Contents/MacOS/firefox --headless --profile .profile --window-size 1024,1024 --screenshot "$*-1024.png" "data:image/svg+xml;base64,$(base64 -b 0 "$*.svg")"
#
endif

%-20.png: %-1024.png			# ターゲットファイル名のパターン:ソースファイル名のパターン—コロンを挟んで左が「$@」右が「$<」
	sips -Z 20 "$<" --out "$@"	# アンチエイリアスで美麗に縮小するために macOS 純正の sips コマンドを利用

%-20@2x.png: %-1024.png
	sips -Z 40 "$<" --out "$@"

%-20@3x.png: %-1024.png
	sips -Z 60 "$<" --out "$@"

%-29.png: %-1024.png
	sips -Z 29 "$<" --out "$@"

%-29@2x.png: %-1024.png
	sips -Z 58 "$<" --out "$@"

%-29@3x.png: %-1024.png
	sips -Z 87 "$<" --out "$@"

%-40.png: %-1024.png
	sips -Z 40 "$<" --out "$@"

%-40@2x.png: %-1024.png
	sips -Z 80 "$<" --out "$@"

%-40@3x.png: %-1024.png
	sips -Z 120 "$<" --out "$@"

%-60@2x.png: %-1024.png
	sips -Z 120 "$<" --out "$@"

%-60@3x.png: %-1024.png
	sips -Z 180 "$<" --out "$@"

%-76.png: %-1024.png
	sips -Z 76 "$<" --out "$@"

%-76@2x.png: %-1024.png
	sips -Z 152 "$<" --out "$@"

%-83.5@2x.png: %-1024.png
	sips -Z 167 "$<" --out "$@"

%-1024.jpg: %-1024.png
	sips -s format jpeg "$<" --out "$@"	# 画像のファイル形式を変換するために macOS 純正の sips コマンドを利用

%-Small-20.png: %-20.png
	cp -p "$<" "$@"			# 既に生成されているものと同一なのでコピーで生成

%-Small-20@2x.png: %-20@2x.png
	cp -p "$<" "$@"

%-Small-29.png: %-29.png
	cp -p "$<" "$@"

%-Small-29@2x.png: %-29@2x.png
	cp -p "$<" "$@"

%-Small-40.png: %-40.png
	cp -p "$<" "$@"

%-Small-40@2x.png: %-40@2x.png
	cp -p "$<" "$@"

clean:			# 生成されたターゲットファイル群をやり直すために全て削除するための PHONY ターゲット
	rm -f $(IMGS) *-1024.png

backup:			# 生成されたターゲットファイル群をバックアップしておくための PHONY ターゲット
	[ -d by_$(headless_browser)/for_ios ] || mkdir by_$(headless_browser)/for_ios
	cp -p $(IMGS) by_$(headless_browser)//for_ios/

ちなみに、%-20.png はターゲットに含まれませんが、%-Small-20.png がターゲットに含まれ、それが %-20.png に依存しているので途中でしっかりと生成されます。しかし、あくまで %-20.png は中間ファイルとなるので、のちに消されます。こうした依存関係に応じて上手く一連の処理を行ってくれるのが make システムなのです。

Written by Taiji Yamada at 2019/12/12, 2022/09/10