
無料Photoshop代替の開発記
色を組み立て直す
チャンネルミキサーで新しい色の数学を発明したわけではありません。既知のRGB加重和を、既存の調整レイヤー、出力選択、定数、保存設定にAIと接続した過程です。
AI生成の動作例用写真。編集画面と出力画像は実際のPhotoshotで作成しました。
ソースから始める。
色を混ぜる計算はすでにあった
元画像のRGBが各出力にどれだけ寄与するかを決める計算は、すでに知られていました。設定保存、マスク、不透明度の合成も既存の基盤です。AIと計算・操作画面・文書構造を同じ機能としてつなぎました。
Adobeの文書は出力チャンネルとモノクロの意味を確認する資料です。以下はPhotoshotの公開実装からの抜粋であり、動作の参考資料とコードの出典を区別しています。
出力と入力のチャンネルを分ける
赤出力の選択は、元画像の赤だけを変える意味ではありません。出力ごとに入力R・G・Bの比率と定数を指定します。三つの出力で数値設定は合計12個です。
0〜1のRGBに各比率を掛け、定数を加えて100で割り、0〜1に制限します。合計表示は案内であり、比率を自動で100%に正規化しません。
L166–184Photoshotの実装コード ↗
mixer: {
name: '채널 혼합',
description: '출력 채널을 원본 RGB 채널의 비율로 만듭니다.',
controls: ['r', 'g', 'b']
.flatMap((c) =>
['R', 'G', 'B', 'Constant'].map((v, i) =>
control(
c + v,
['빨강', '초록', '파랑', '상수'][i],
-200,
200,
c === v.toLowerCase() ? 100 : 0,
1,
c,
),
),
)
.concat(control('mono', '단색', 0, 1)),
},計算の
内側へ。
定数と不透明度は別の段階
定数+10は成分に0.1を加えるため、明るい値は上限に達する場合があります。不透明度は計算後の画像と元画像を合成する段階で働きます。
説明用RGB 170・130・110の赤と青を交換すると110・130・170。70%で合成すると丸め前は128・130・152です。写真から採取した測定値ではありません。
同じ構造でモノクロも扱う
モノクロでは、すべての出力が赤出力の設定を読みます。同じ加重和をR・G・Bに入れるのでグレーになります。
9回の白黒調整は色相を六つの範囲に分ける方式でした。チャンネルミキサーのモノクロはRGB成分を重み付けする方式です。似た見た目でも操作する基準が違います。
コードを読む。
L720–727Photoshotの実装コード ↗
if (t === 'mixer') {
for (let c = 0; c < 3; c++) {
const key = v.mono ? 'r' : 'rgb'[c];
out[c] = clamp(
(r * v[key + 'R'] + g * v[key + 'G'] + b * v[key + 'B'] + v[key + 'Constant']) / 100,
);
}
}L836–853Photoshotの実装コード ↗
beforeRGB: RGB = [0, 0, 0],
mixed: RGB = [0, 0, 0];
for (let i = start; i < end; i += 4) {
if (!data[i + 3]) continue;
let amount = opacity * (mask ? mask[i + 3] / 255 : 1);
if (blend === 'dissolve') amount = pixelNoise(i / 4) < amount ? 1 : 0;
if (!amount) continue;
compiled(data[i], data[i + 1], data[i + 2], out);
for (let c = 0; c < 3; c++) beforeRGB[c] = data[i + c] / 255;
if (a.values.dither && (a.type === 'lookup' || a.type === 'gradient'))
for (let c = 0; c < 3; c++) out[c] = clamp(out[c] + (pixelNoise(i / 4) - 0.5) / 255);
blendRGB(beforeRGB, out, blend, mixed);
for (let c = 0; c < 3; c++)
data[i + c] = Math.round(clamp(beforeRGB[c] + (mixed[c] - beforeRGB[c]) * amount) * 255);
}
}L253–265Photoshotの実装コード ↗
export function isIdentityAdjustment(a: Adjustment): boolean {
if (a.type === 'lookup') return !a.cube;
if (a.type === 'curves') return channels.every((c) => a.curves![c].every((p) => p.x === p.y));
if (a.type === 'photo') return a.values.density === 0;
if (['blackwhite', 'gradient', 'invert', 'posterize', 'threshold'].includes(a.type)) return false;
if (a.bands?.some((b) => b.hue || b.saturation || b.lightness)) return false;
return definitions[a.type].controls.every(
(c) =>
['preserve', 'relative', 'skin', 'legacy', 'colorizeHue', 'colorizeSaturation'].includes(
c.key,
) || (a.values[c.key] ?? c.initial) === c.initial,
);
}エディターで見る。

写真とコードを照合する
保存プロジェクトと実画面はMonochromeオン、Red 21・Green 72・Blue 7・Constant 0、不透明度100%です。AI生成の人物画像を実際のPhotoshotで編集し、書き出しました。
本日、公開コードの16調整について恒等変換、アルファ、保存往復、合成の一致を再確認しました。Photoshop全体との同等性を示す検査ではありません。次回は外部の色変換表を読むカラールックアップです。
写真で見る結果。


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