メインコンテンツにスキップ
Tech & Program 記事一覧に戻る
📐

TeXのTikZでSVGのアイコンを作ってみる。

このウェブサイトの favicon をどうしようかと思っていたところ、普段から使っている TikZ で作ればいいじゃんとなったので、作る流れなどを備忘録として残しておきます。

TeX TikZ Design

このサイトを立ち上げてからずっと、favicon をどうするかを決めきれずにいました。とりあえずの仮アイコンは置いてあるものの、適当なロゴ作成サイトでテンプレートを使って作ったやつなので,「ちゃんと自分のサイトらしいアイコンがほしいな〜」とずっと思っていました。

とはいえ、普段からアイコンを描いているわけでもないし、Illustrator 持ってないし、新しいアプリで 0 から作るのも腰が重い……。そこでふと、「普段から書き慣れている TeX + TikZ でベクター画像をつくればよくない?」となったので、実際に TikZ で SVG のアイコンを作ってみました。

この記事では、

  • どんなアイコンを目指したか
  • TikZ でどうやって図形を組み立てたか
  • 最終的に SVG に書き出すまでの流れ

あたりを、ほぼ自分用メモとして残しておきます。

目指したアイコンのイメージ

せっかく TeX / TikZ で描くので、幾何っぽい数学的な図形でというのをテーマに作ってみました。

条件としてはこんな感じです。

  • シンプルな図形: favicon は小さく表示されがちなので、ある程度シンプルじゃないと図形が潰れてしまう。
  • 色数は少なめ: テーマカラー 1 色 + 明暗の変化くらい
  • TikZ ベタ書きで完結できる: 外部画像なしで、TikZ が活きるような数式で書けるような図形。

そこで、斜めに切り分けた平行四辺形をベースに、N の輪郭に切れ込みを入れて W っぽく見えるような図形を、とりあえず Geogebra で作ってみました。

Geogebraで試作したNとWが重なった図形

TikZでの実装

とりあえず、Geogebra の図のまま点を配置して描画してみます。

\begin{tikzpicture}[>=stealth, scale=0.8]
\def\height{9}
\def\width{9}
\def\diff{\height/3}

\def\Rate{100}
\def\opacity{1}
\definecolor{myC}{HTML}{0044FF}
\coordinate (LU) at (-\diff, \height);
\coordinate (LD) at (0, 0);
\coordinate (RD) at (\width, 0);
\coordinate (RU) at (\width-\diff, \height);


\coordinate (LUd) at (0, \height);
\coordinate (LDd) at (\diff, 0);
\coordinate (RDd) at (\width+\diff, 0);
\coordinate (RUd) at (\width, \height);

\coordinate (LP) at (intersection of LD--RU and LUd--LDd);
\coordinate (RP) at (intersection of LDd--RUd and RU--RD);
\fill[fill=myC!\Rate, opacity=\opacity] (LP) -- (LDd) -- (RP) -- (RU) -- cycle;
\fill[fill=myC!\Rate, opacity=\opacity] (LU) -- (LUd) -- (LP) -- (LD) -- cycle;
\fill[fill=myC!\Rate, opacity=\opacity] (RP) -- (RUd) -- (RDd) -- (RD) -- cycle;
\end{tikzpicture}

これをコンパイルするとこんな感じ。

TikZで描画した最初のアイコン案

ここで出てきた TikZ のお作法を、本当にざっくりだけ整理しておきます。 \coordinate で点を定義できて、(名前) at (座標) という書き方が基本です。ここで座標のところに数値ではなく intersection of A--B and C--D と書くと、「直線 AB と直線 CD の交点」に点を置くことができます。 また、色については \definecolor でカラーコードなどから色を定義しておき、myColor!50!black, opacity=0.6 のように書くことで、色同士を混ぜたり透明度を指定したりできます。

改良

最初の版だと、平行四辺形同士の境目が「ただの交点」になっていて、少しカクカクした印象でした。ここにもう少しだけ「厚み」や「丸み」を持たせたいなと思い、最初は双曲線や二次関数を載せることも考えたのですが、パラメータ調整(特に側面にきれいに接するようにする調整)が面倒そうだったので、デザイン界隈ではおなじみの ベジェ曲線 を TikZ で使ってみることにしました。

\def\curveFactor{0.4} 
% 右側の曲線 (RP 周り)
\draw[very thick, red] 
    ($(RP)!\curveFactor!(RU)$) .. controls (RP) .. ($(RP)!\curveFactor!(RUd)$);
\draw[very thick, red] 
    ($(RP)!\curveFactor!(RD)$) .. controls (RP) .. ($(RP)!\curveFactor!(LDd)$);

% 左側の曲線 (LP 周り)
\draw[very thick, red] 
    ($(LP)!\curveFactor!(LD)$) .. controls (LP) .. ($(LP)!\curveFactor!(LDd)$);
\draw[very thick, red] 
    ($(LP)!\curveFactor!(LUd)$) .. controls (LP) .. ($(LP)!\curveFactor!(RU)$);

これを追加してコンパイルするとこんな感じ。

ベジェ曲線で角を丸めた最終版のアイコン
この `.. controls (RP) ..` の 1 本だけ取り出すと、次のような二次ベジェ曲線になっています。
  1. 各点の決め方

登場する 3 点を P0,P1,P2P_0, P_1, P_2 とします。

  • 始点 P0P_0: ($(RP)!\curveFactor!(RU)$)
    ベクトル表記では P0=(1f)RP+fRUP_0 = (1-f)\,\mathrm{RP} + f\,\mathrm{RU}ff\curveFactor
  • 制御点 P1P_1: (RP)
  • 終点 P2P_2: ($(RP)!\curveFactor!(RUd)$)
    ベクトル表記では P2=(1f)RP+fRUdP_2 = (1-f)\,\mathrm{RP} + f\,\mathrm{RUd}
  1. 数式としての定義(媒介変数表示)

この二次ベジェ曲線上の点 B(t)B(t)t[0,1]t \in [0,1])は、

B(t)=(1t)2P0+2(1t)tP1+t2P2B(t) = (1-t)^2 P_0 + 2(1-t)t P_1 + t^2 P_2

と書けます。制御点が 1 つなので形としては「放物線の一部分」になり、これを 4 か所に仕込むことで全体が少しだけ丸く見えるようにしています。もう少し直感的に言うと、各辺について左右が均等にならない位置に内分点を取り、その点を通るベジェ曲線で角を少しだけ丸めているイメージです。

ベジェ曲線まわりの点と曲線の関係を示した図

この図を見ると、どの辺にどんなベジェ曲線を仕込んでいるかが視覚的に分かりやすいと思います。内分点を取らずにやると辺にべったりと曲線が張り付いたような感じになってしまうので、内分点を端点としたベジェ曲線を作っています。

色を調整する

\definecolor{left}{HTML}{00A4A5}
\definecolor{right}{HTML}{40e0d0}
\definecolor{line}{HTML}{FFFFFF}

\pgfdeclarehorizontalshading{leftRightShading}{100bp}{
  color(0bp)=(left);
  color(100bp)=(right)
}

\tikzset{GradStyle/.style={
    preaction={draw=black, draw opacity=0.32, line width=1.60pt, line join=round},
    shade,
    shading=leftRightShading,
    shading angle=150,
    fill opacity=0.85,
    draw=line,
    draw opacity=0.90,
    line width=1.15pt,
    line join=round
}}

こんな感じでグラデーションを定義します。この GradStyle(コード中では glassStyle)を \fill に使えば、うっすらとしたグラデーションが得られます。白で縁取りもしています。

  \def\curveFactor{0.4}
  \fill[glassStyle]
  (LD)
  -- ($(LP)!\curveFactor!(LD)$) .. controls (LP) .. ($(LP)!\curveFactor!(LDd)$)
  -- (LDd)
  -- ($(RP)!\curveFactor!(LDd)$) .. controls (RP) .. ($(RP)!\curveFactor!(RD)$)
  -- (RD)
  -- (RDd)
  -- (RUd)
  -- ($(RP)!\curveFactor!(RUd)$) .. controls (RP) .. ($(RP)!\curveFactor!(RU)$)
  -- (RU)
  -- ($(LP)!\curveFactor!(RU)$) .. controls (LP) .. ($(LP)!\curveFactor!(LUd)$)
  -- (LUd)
  -- (LU)
  -- cycle;

これをコンパイルするとこんな感じです。グラデーションは若干薄いので、left の色をもう少し濃くしたほうがよいかなとも思いつつ、この形で favicon を作ってしまいました。

グラデーションと白の縁取りをしたfaviconの背景透明化

SVG への書き出し

最終的には、この TikZ 図を SVG として書き出して favicon に使うのがゴールです。

方法としては、例えば次のようなものがあります。

  • DVI → SVG: dvisvgm で DVI から直接 SVG を生成する
  • PDF → SVG: いったん PDF にコンパイルしてから、PDF を SVG に変換する

私は手元で「PDF → SVG」の流れを取っています。PDF からの変換には、Poppler に含まれる pdftocairo を使っています(pdf2svg でも同様のことができます)。このサイトでは、TeX ソースを public/images/favicon/favicon.tex に置き、次のような手順で SVG と PNG を出しています。

実際の処理

1. TeX を PDF にコンパイルする

TeXshopを使ってるので,割愛。 favicon.pdf ができれば OK です。

2. PDF から SVG を生成する

PDF が 1 ページなら、pdftocairo -svg で 1 枚の SVG が得られます。そのままではファイル名に -1 が付くので、リネームしてから、favicon 用に width / height を 32 にしておく例です。

# プロジェクトルートで実行する想定
FAVICON_DIR="public/images/favicon"
PDF="$FAVICON_DIR/favicon.pdf"
OUT_SVG="$FAVICON_DIR/favicon.svg"
TMP_BASE="$FAVICON_DIR/.favicon-svg-tmp"

pdftocairo -svg "$PDF" "$TMP_BASE"
mv "${TMP_BASE}-1.svg" "$OUT_SVG"

# favicon 用に width/height を 32 に(viewBox はそのまま)
sed -i '' 's/width="[^"]*" height="[^"]*"/width="32" height="32"/' "$OUT_SVG"   # macOS
# sed -i 's/width="[^"]*" height="[^"]*"/width="32" height="32"/' "$OUT_SVG"  # GNU sed
  • pdftocairo -svg: PDF の各ページを SVG に変換します。1 ページの場合は -1.svg という名前で出るので、それを favicon.svg にリネームしています。
  • sed: 出力 SVG の <svg> タグにある width / height32 に書き換えています。viewBox は触らないので、拡大縮小はブラウザ任せで、favicon として扱いやすくするための指定です。sed -i '' は macOS、GNU 環境では sed -i だけにします。

まとめて実行するスクリプト(scripts/favicon-svg-from-pdf.sh)もリポジトリに用意してあり、favicon.pdf を更新したあと ./scripts/favicon-svg-from-pdf.sh を叩くだけで SVG を再生成するようにしています。PNG もまとめて出したい場合は scripts/favicon-from-pdf.sh を使うと、16×16 / 32×32 / 48×48 の PNG と SVG を一括で作り直せます。

出力した SVG を必要に応じてエディタで軽く整えてから、このサイトの favicon として配置しています。

おわりに

普段から書き慣れている TeX / TikZ だけで、意外とそれっぽいアイコンが作れてしまいました。特に、交点計算座標の線形結合が簡単に書けるおかげで、「ちょっと形を変えたい」と思ったときの試行錯誤がとても楽です。

この記事のコードをベースに、色や形、曲率などを変えて遊んでみるだけでも結構楽しいので、「TeX は論文を書くためのもの」というイメージをお持ちの方も、ぜひ TikZ でロゴやアイコンを作ってみてください。