見出し画像

After Effects エフェクトプラグインをゼロから作って見よう 7回目 "ColorChange/ColorSelect"

今回は色関係のエフェクトで一番簡単な"ColorChamge/ColorSelect"を作ってみました。
F's PluginsF's ColorChange.aex/F's SelectColor.aexになります。
あまりにも簡単なので若干の機能追加もしています。


Download

いつも通りgithubで公開しています。今はバラバラですがある程度まとまったらRelease版も作ります。

NF-ColorChage.aex / NF-ColorSelect.aex こちらは直りんです(古いバージョンの可能性あります)

NF-ColorChange.aex

カラーチェンジ(色変え)エフェクトです。

F's ColorChangeと同じですが、ターゲット色が8色から16色に後、IOというカテゴリを増やしています。とりあえず各パラメータの説明です。

IO/ dispColorTable カラーテーブル描画

下のカラーチェンジテーブルを描画します。なんとなくわかりやすくなるかなと。
左の駒は白が有効(ON)、黒は非有効(OFF)状態としています。srcカラーが同じものがあるとエフェクトコントロールでONになっていてもこちらでもOFFになります。

IO/ dispUseColor 使用色の一覧

カレントフレームでの描画されている色の一覧を表示します。使われている色の最大48色まで描画しています。スポイトで色を拾うときに便利かなと。
dispColorTableもそうですがONにしておくとレンダリング時にも描画されてしまうので注意してください。

ExportColors/ImportColors

下のカラーテーブルを書き出し・読み込みするボタンです。押すとダイアログが表示されて読み込み・書き出しができます。
ファイルは通常のJSON形式のファイルになっていますが、わかりやすいように拡張子を".ccj"(ColorChangeJson file)にしています。
今まで僕はプリセットファイル(ffx)で保存していましたが、まぁファイルにしてもいいかなと。

{
    "level": 0.0
    "ctable": [
        {
            "dst": {
                "blue": 17,
                "green": 57,
                "red": 163
            },
            "enabled": true,
            "index": 0,
            "src": {
                "blue": 193,
                "green": 205,
                "red": 223
            }
        },

こんな感じになっています。保存するのはカラーテーブルLevelのみです。
index項目がありますが読み込み時には反映されません。順番は配列の順番が優先されます。まぁ見やすい事と編集時に面倒じゃないかなと。

ColorTable / enabled

色変更を行うかどうかのフラグです。

ColorTable / enable? | src? | dst?

enable?がONでsrc?/dst?の色変換が有効になります。
src?/dst?が同じ色の場合も内部でenable?はOFF扱いにしています。
src?が他にも同じ色が指定されていたらそれもOFFになるようにしています。

NF-ColorSelect

これは選択色のピクセルのみ残して他は透明にするエフェクトです。

各パラメータはNF-ColorChangeと同じなので説明は省略します。

ColorTable / rev

一つだけ説明します。
revはONにすると透明・不透明部分が反転して、選択した色だけを不透明にするエフェクトになります。
まぁ、これは色を選ぶときに選ぶとその他の色が消えてしまって選びにくいので付けた機能です。便利かなと。

NF-ColorChangeの内部

static PF_Err
ColChange16(
	void* refcon,
	A_long		xL,
	A_long		yL,
	PF_Pixel16* inP,
	PF_Pixel16* outP)
{
	PF_Err			err = PF_Err_NONE;
	ParamInfo* infoP = reinterpret_cast<ParamInfo*>(refcon);

	for (int i = 0; i < COLOR_MAX; i++)
	{
		if (infoP->colorTable[i].Enabled == FALSE) continue;

		if (compPix16_8Lv(*inP, infoP->colorTable[i].Src, infoP->lv_byte) == TRUE)
		{
			*outP = infoP->colorTable[i].Dst16;
		}
	}
	return err;
}

上のコードは16bitモード時のエフェクトになります。
16bitでも、色の判定は8bitの色でやってるのがポイントです。
compPix16_8Lv()がこれ専用で作ったインライン関数になります。
F’s ColorChangeの時はカラーテーブルは高速化のため使用していない色は除いたカラーテーブルを別に作成していましたが、最近はすごい早いのでバグ発生の要因を減らすため単純にしています。

	//----------------------------------------------------------------
	AEFX_CLR_STRUCT(def);
	PF_ADD_CHECKBOX(
		"rev",
		"on",
		FALSE,
		0,
		ID_REV
	);
	//----------------------------------------------------------------
	for (int i = 0; i < COLOR_MAX; i++)
	{
		int idx = ID_CTABLE(i);
		std::string c;
		std::string idxStr = std::to_string(i);

		//----------------------------------------------------------------
		AEFX_CLR_STRUCT(def);
		c = std::string("enable") + idxStr;
		PF_ADD_CHECKBOX(
			c.c_str(),
			"on",
			FALSE,
			0,
			idx
		);
		c = std::string("src") + idxStr;
		AEFX_CLR_STRUCT(def);
		PF_ADD_COLOR(
			c.c_str(),
			0xFF,
			0xFF,
			0xFF,
			idx+1
		);
	}
//--------------------------------------
#define ID_CTABLE(idx) (ID_CTABLE_ST + idx*3 )
#define ID_TOPIC_CTABLE_END (ID_CTABLE_ST + COLOR_MAX*3)
#define ID_NUM_PARAMS  (ID_TOPIC_CTABLE_END+1)


上のコードはParamSetupでUIの登録を行っている部分ですが、同じものを16個も並べて書くのはあまりにも面倒なのでコードで処理しています。手抜きで文字列処理はstd::stringを使ってます。その他ファイルダイアログも入れたのでファイルサイズが少し大きくなりました。
インデックス番号はマクロで処理しています。

PF_Cmd_USER_CHANGED_PARAMセレクタ

今回初めてUIにボタンを使ったので調べてみました。
Buttonのイベントは新規にイベント設定しなくても、PF_Cmd_USER_CHANGED_PARAMセレクタで拾えます。
引数に変化したUIのインデックス番号があるのでそれでボタンと判断できます。
PF_Cmd_USER_CHANGED_PARAMセレクタで呼び出されたタイミング中では、UIの値を直接書き換えることができるので、suite関係を呼び出す手間もなく簡単でした。

PF_Err	 ColorChange::UserChangedParam(
	PF_InData* in_dataP,
	PF_OutData* out_dataP,
	PF_ParamDef* paramsP[],
	PF_LayerDef* outputP,
	PF_UserChangedParamExtra* extraP,
	A_long pc)
{
	PF_Err err = PF_Err_NONE;
	Init(in_dataP, out_dataP, paramsP, outputP,ID_NUM_PARAMS);
	m_cmd = PF_Cmd_USER_CHANGED_PARAM;
	if (extraP->param_index == ID_BTN_SAVE)
	{
		std::string p = SaveJsonFileDialog(std::string("Json Save"), directoryPath);
		if (p.empty() == FALSE)

これはNFライブラリの仕様で各イベントごとに呼び出された場合、Init()で初期化する必要があります(m_cmdメンバの設定も)通常ならほとんど意識しなくて大丈夫ですが、今回みたいにoverrideして使うときに注意しないとはまります。

PF_Err SetCHECKBOX(A_long idx, PF_Boolean b)
{
	PF_Err err = PF_Err_NONE;
	if ((idx >= 1) && (idx < m_paramsCount) && (m_cmd == PF_Cmd_USER_CHANGED_PARAM)) {
		params[idx]->u.bd.value = b;
		params[idx]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE;
	}
	else {
		err = PF_Err_INVALID_INDEX;
	}
	return err;
}

上記はCheckboxの値を設定するコードですが、構造体に書き込んだ後、uu.change_flagsに変更したフラグを設定すればUIに反映されます。

最後に

ColorChangeってF'sの時は1時間かけずに作った記憶あります。
色替えのリテークを撮影でって言われてサクッと作ったと思います。
簡単に作った割には長く使ってるエフェクトです。

今回もサクッとできましたが、おまけでパラメータの読み込み書き込みの機能をつけてみました。
こんな感じにF's Pluginsからの移植していきます。

いいなと思ったら応援しよう!