GitHub の初期アイコン (identicon) の角だけを丸める painless-ghicon を作った

painless-ghicon は、GitHub の初期アイコン (identicon) のブロックパターンの角だけを丸める Rust 製のツールです。色とブロックの配置は一切変えず、直角の角だけを滑らかにするため、変換後も一目で同じアイコンだとわかります。この記事では、painless-ghicon を作った動機と CLI の使い方、内部の角丸アルゴリズムについて紹介します。

愛着のある初期アイコンを少しだけ変えたい

GitHub のアカウントを作成すると、ユーザー ID のハッシュ値から自動生成されたブロックパターンのアイコン、いわゆる identicon がプロフィール画像として設定されます。左右対称の 5x5 グリッドに 1 色のブロックが並ぶだけの簡素な画像ですが、長く使っていると「自分の顔」として愛着が湧いてくるものです。僕も長年この初期アイコンのまま過ごしてきて、いまさら別の画像に差し替える気にはなれませんでした。

一方で、少し不満もありました。直角のブロックがカクカクと並ぶ見た目はどこか素っ気なく、角丸のアイコンが主流の昨今の UI に並ぶと硬い印象を受けます。かといって描き直したり別の画像にしたりすれば、せっかく定着した「自分らしさ」が失われてしまいます。

そこで「色も配置も変えず、ブロックの角だけを丸める」という発想で作ったのが painless-ghicon です。変換の前後を並べると、次のようになります。

変換前 変換後
変換前の identicon 変換後の identicon

ブロックの配置と色はそのままに、外側に飛び出た角 (凸角) も、ブロック同士が接する入り組んだ角 (凹角) も滑らかに丸まっていることがわかりますね。丸め具合は後述する --ratio オプションで調整でき、この例はデフォルト値の 0.4 で変換したものです。正方形のキャンバスには手を付けないので、変換後の画像をそのままプロフィール画像としてアップロードしても違和感がありません。

painless-ghicon をインストールする

macOS / Linux では、リリースページのシェルインストーラーでビルド済みバイナリをインストールできます。

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/takumi3488/painless-ghicon/releases/latest/download/painless-ghicon-installer.sh | sh

Warning

リモートスクリプトをパイプ実行する際は、内容を確認してから実行してください。インストーラーの中身は リリースページ からダウンロードして確認できます。

Windows (x64) の場合は 最新リリース から zip をダウンロードし、painless-ghicon.exe を PATH の通った場所に配置します。Rust のツールチェーンがあるなら、任意のプラットフォームでソースからインストールすることもできます。

cargo install --git https://github.com/takumi3488/painless-ghicon painless-ghicon

CLI でアイコンを変換する

インストールできたら、まずは --help でオプションを確認してみましょう。

$ painless-ghicon --help
Rounds the corners of GitHub identicon block patterns.

Usage: painless-ghicon [OPTIONS] <SOURCE>

Arguments:
  <SOURCE>  Path to a local PNG/JPEG file, a GitHub user ID, or a GitHub user URL.

Options:
  -r, --ratio <RATIO>    Corner radius as a fraction of the detected block size, in (0.0, 0.5] (0.5 = full circles). [default: 0.4]
  -o, --output <OUTPUT>  Output PNG path. Defaults to a name derived from the source.
  -h, --help             Print help
  -V, --version          Print version

引数はローカルの画像ファイルのパス、GitHub のユーザー ID または URL のいずれか 1 つだけです。まずはリポジトリに同梱されているサンプルの identicon を手元に保存し、ファイルパスを渡して変換してみましょう。

$ curl -sLO https://raw.githubusercontent.com/takumi3488/painless-ghicon/main/samples/takumi3488.png
$ painless-ghicon takumi3488.png
takumi3488-rounded.png

出力ファイル名を省略すると、<元のファイル名>-rounded.png という名前で保存されます。自分のアイコンを変換する場合は、画像を保存しなくても GitHub のユーザー ID や URL を渡せば、アバター画像のダウンロードから変換までを一度に実行できます。

painless-ghicon octocat
painless-ghicon https://github.com/octocat
Note

painless-ghicon は「背景と前景の 2 色で構成されたブロックパターン」を前提に変換を行います。イラストや写真をプロフィール画像にしている場合、その画像は 2 色に潰されてしまうため、変換対象は自動生成された identicon に限るのが無難です。

--ratio で丸め具合を調整する

--ratio オプションには、ブロック 1 辺の長さに対する角丸半径の比率を 0.0 より大きく 0.5 以下の範囲で指定します。デフォルトは 0.4 です。値を変えて同じ画像を変換し、見た目を比べてみましょう。

painless-ghicon takumi3488.png --ratio 0.1 --output takumi3488-ratio0.1.png
painless-ghicon takumi3488.png --ratio 0.5 --output takumi3488-ratio0.5.png
--ratio 0.1 --ratio 0.4 (デフォルト) --ratio 0.5
ratio 0.1 の変換結果 ratio 0.4 の変換結果 ratio 0.5 の変換結果

0.1 では元のブロックのシルエットをほぼ保ったまま、角にごくわずかな丸みが付く程度です。デフォルトの 0.4 でははっきりと丸みが視認でき、スマートフォンのアプリアイコンのような柔らかい印象に変わります。最大値の 0.5 まで上げると、周囲と接していない孤立したブロックは完全な円になります。どの値でも正方形のキャンバス自体はそのままなので、丸め具合はアイコンとしての使い勝手を気にせず好みだけで選べます。

「角だけ」を丸める仕組み

painless-ghicon のコアロジックは、大きく「パターン検出」と「角丸処理」の 2 段階に分かれています。角丸処理は SVG や CSS の border-radius のような図形描画のやり直しではなく、入力画像だけを手がかりにしたピクセルベースの画像処理です。

2 色とセルサイズを自動検出する

identicon は「単色の背景 + 単色のブロック」という構造なので、まず画像の外周 1 ピクセルに出現する色の最頻値を背景色とみなします。次に、背景色から一定以上離れた色のピクセルを集計して前景色を決定します。前景ピクセルが画像全体の 0.5% に満たない場合は「2 色のブロックパターンではない」と判断して変換を中止するため、identicon 以外の画像をうっかり壊しにくくなっています。

ブロック 1 辺の長さ (セルサイズ) は、前景ピクセルが縦・横方向に連続する区間 (run) の最短長から推定します。identicon のブロックはすべて同じ大きさの正方形なので、最も短い連続区間がちょうど 1 ブロック分の長さになるというわけです。

距離変換でクロージングとオープニングを行う

角丸処理の本体は、画像処理の古典であるモルフォロジー演算 (morphological operation) です。前景の形状に対して、まず膨張してから収縮するクロージング (closing) で凹角を埋め、続けて収縮してから膨張するオープニング (opening) で凸角を削ります。この 2 つを組み合わせることで、内側と外側の両方の角が同じ半径で丸まります。

膨張・収縮の判定には、各ピクセルから前景までの正確なユークリッド距離を使っています。距離の計算には Felzenszwalb & Huttenlocher の距離変換アルゴリズムを実装しています。放物線の下側包絡線を求める 1 次元の距離変換を行・列方向に 2 回適用することで、画像サイズに対して線形時間で厳密な距離マップが得られます。近似ではなく厳密な距離を使っているため、丸めた角は幾何学的に正しい円弧になります。

角丸半径 (radius) は、セルサイズ (cell_f) に --ratio の値を掛けて求め、セルサイズの半分よりわずかに小さい値を上限としています。

let radius = (f64::from(radius_ratio.clamp(0.0, 0.5)) * cell_f).min(cell_f / 2.0 - 1.0);

--ratio 0.5 では角丸半径がブロック 1 辺の半分に達するため、孤立したブロックはちょうど完全な円になります。

距離から被覆率を計算してアンチエイリアスをかける

最後に、丸めた形状の輪郭を滑らかに見せるためのアンチエイリアス (anti-aliasing) です。各ピクセルについて「丸めた形状の芯からの距離」と半径の差からピクセルの被覆率 (coverage) を計算し、その値で背景色と前景色を線形補間します。以下は該当箇所を簡略化した抜粋です。

let coverage = (1.0 - (dist_to_core[index].sqrt() - radius)).clamp(0.0, 1.0);
for channel in 0..3 {
    let blended = f64::from(pattern.bg[channel])
        + (f64::from(pattern.fg[channel]) - f64::from(pattern.bg[channel])) * coverage;
    pixel[channel] = blended.round() as u8;
}

輪郭がジャギーにならず滑らかに見えるのはこの補間のおかげです。テストコードでは、--ratio 0.5 で孤立ブロックを変換した結果が理論上の円の面積と 15% 未満の誤差に収まることまで検証しています。

変換対象が「自動生成された identicon」に限られる分、色や配置の検出からアンチエイリアスまでを全自動で行えるのがこのツールの割り切りです。僕自身、現在の GitHub のプロフィール画像はこのツールでデフォルトの --ratio 0.4 を使って変換したものに差し替えました。初期アイコンへの愛着を保ったままプロフィール画像の印象を柔らかくしたい人には、ちょうどよい道具になっているのではないでしょうか。

まとめ

  • painless-ghicon は GitHub の初期アイコン (identicon) のブロックの角だけを丸める Rust 製ツールであり、色とブロック配置は一切変更しない
  • CLI はローカル画像のパスのほか GitHub のユーザー ID や URL を直接受け取り、--ratio で丸め具合を 0.5 (完全な円) まで調整できる
  • 内部では 2 色とセルサイズの自動検出を行い、厳密なユークリッド距離変換に基づくクロージングとオープニングで凹凸両方の角を丸めている
  • 変換対象は 2 色のブロックパターンに限られるため、イラストや写真のアバターには不向きで、初期アイコンを使い続けている人向けのツールである

参考