
無料Photoshop代替の開発記
色の範囲を選ぶコード
色相を変える実装やRGB・HSL変換はすでにありました。しかし写真で選んだ色を、編集できる範囲につなぐ作業は残っていました。Photoshotの色相・彩度は、範囲計算、スポイト、設定保存を既存エンジンへAIと接続した例です。
AI生成の動作例用写真。編集画面と出力画像は実際のPhotoshotで作成しました。
ソースから始める。
色変換だけでは操作できる道具にならない
HSLの式があることと、写真の青を選んで調整できることは別の段階です。既存の色変換とマスクに、範囲の境界、画面入力、保存ルールをつなぐ必要がありました。AIはその間のコードの作成と修正に使いました。
既存のエンジンにはRGBとHSLの変換関数、マスクとレイヤー不透明度を扱う共通処理がありました。そこに色範囲を保存するbandsと、画像から色を拾うツールを接続しました。
初期セッションにはKonvaのHSL.tsを参照した記録もあります。ただし、それだけで範囲選択コードをコピーしたとは言えません。ここで示すのはGitHubに公開したポトショット自身の実装です。外部フィルターの導入と、既存エンジンへの追加実装を区別しています。
359度と1度は隣り合う色
普通に引き算すると359度と1度の差は358度ですが、色相環では赤を挟んだ隣の色です。剰余演算で差を−180〜180度に折り返してから絶対値を取ると、距離は2度になります。
その距離をオン・オフの判定ではなく重みwに変換します。中心範囲では1、ぼかし領域では徐々に小さくなり、外側で0になります。色相・彩度・明度の変化量に同じ重みを掛けています。
色相環の距離は既知の考え方です。実装の課題は、その距離を各調整量に共通する重みに結び付けることにあります。AIと書いた接続コードが、独立した式を編集できる設定に変えます。
L603–610Photoshotの実装コード ↗
if (!v.colorize)
for (const band of a.bands ?? []) {
const d = Math.abs(((h * 360 - band.center + 540) % 360) - 180),
w = clamp(1 - (d - band.width / 2) / band.feather);
hue += band.hue * w;
sat += band.saturation * w;
light += band.lightness * w;
}計算の
内側へ。
範囲とぼかしを数値で読む
写真例の青の範囲は中心240度、幅30度、ぼかし30度です。中心から15度以内は全量、30度離れると半分、45度以上では0になります。幅30度は左右それぞれ30度という意味ではありません。
スポイトは選んだ画素の色相を計算し、最も近い色グループの中心を変更します。ほぼ灰色の画素は色相を適切に決めにくいため受け付けません。クリックした位置を、後から編集できる設定値へ変換するのが役割です。
彩度と明度の計算にも版を持たせる
revision 2では、正の彩度値に使う倍率を変更しました。例えば+50は、この経路では1.5倍ではなく1÷(1−0.5)、つまり2倍です。最終的な彩度は許容範囲に制限します。
明度もHSLのLだけを直接変えるのではなく、RGB各成分を調整してからHSLへ再変換します。以前のプロジェクトは従来の計算を維持します。AIにスライダーを追加してもらう作業と、保存結果を守りながら計算を直す作業は別でした。
コードを読む。
L45–48Photoshotの実装コード ↗
const bands = structuredClone(a.bands ?? makeAdjustment('hsl').bands!);
const i = Math.round(hue / 60) % 6;
bands[i].center = hue;
return { ...a, bands };L619–626Photoshotの実装コード ↗
const ns = v.colorize
? v.colorizeSaturation / 100
: clamp(
inputS *
(a.revision === 2 && sat > 0
? 1 / Math.max(0.0001, 1 - sat / 100)
: 1 + sat / 100),
),L614–618Photoshotの実装コード ↗
if (a.revision === 2) {
const lit = (x: number) =>
light < 0 ? x * (1 + light / 100) : x + ((1 - x) * light) / 100;
[inputH, inputS, inputL] = hsl(lit(r), lit(g), lit(b), scratch);
}エディターで見る。

色範囲の選択と物体選択は別
保存済みの例は、青の範囲に色相−25、彩度+15を適用し、全体の色相・彩度・明度を0にしています。AI生成の人物写真を使った動作例で、Photoshopとの数値一致試験ではありません。
分散した機能を組み合わせるとは、外部パッケージを複数導入することだけではありません。既存の変換関数やマスクに新しい選択コードをつなぐのも同じ仕事です。AIは、それらが共通の文書と設定で動く実装を助けました。
青い服だけでなく青い背景も変わり得ます。服だけを対象にするならレイヤーマスクを併用します。次回のカラーバランスでは、色相ではなくシャドウ・中間調・ハイライトを分けます。
写真で見る結果。


AI生成の動作例用写真。編集画面と出力画像は実際のPhotoshotで作成しました。