TL;DR
- ScriptListenerで出力されたJSファイルを参考にした
- ColorBookの解析が必要だった
- なぜなら、カラーブックに紐づくIDと特色に紐づくIDが必要だったから
はじめに
Photoshop上で、特色を設定する際の動作をスクリプト化したかった。
具体的には、以下の動作をスクリプト化したかった。
検証環境
MacOS 10.13.6
Adobe Photoshop CC 2018
ScriptListenerで動作を調べてみよう
ScriptListenerについては、Adobe公式サイトを参照ください。
使い方も調べればいくつも見つかると思います。
一応、どういうものかについて、上記サイトの一文を引用しておきます。
ScriptingListener プラグインは、実行可能な操作のログファイルに Java スクリプトを記録できます。
実行結果をのぞいてみよう
ScriptListenerを有効にして、特色を割り当ててみます。
その結果書き出されたログファイルを全て載せると長いので、該当箇所だけ抜粋すると以下の様なコードになっていました。
var idsetd = charIDToTypeID( "setd" );
var desc8 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref1.putEnumerated( idChnl, idOrdn, idTrgt );
desc8.putReference( idnull, ref1 );
var idT = charIDToTypeID( "T " );
var desc9 = new ActionDescriptor();
var idNm = charIDToTypeID( "Nm " );
desc9.putString( idNm, """ANPA 71-1 AdPro""" );
var idClr = charIDToTypeID( "Clr " );
var desc10 = new ActionDescriptor();
var idBk = charIDToTypeID( "Bk " );
desc10.putString( idBk, """ANPA J[""" );
var idNm = charIDToTypeID( "Nm " );
desc10.putString( idNm, """ANPA 71-1 AdPro""" );
var idbookID = stringIDToTypeID( "bookID" );
desc10.putInteger( idbookID, 3000 );
var idbookKey = stringIDToTypeID( "bookKey" );
desc10.putData( idbookKey, String.fromCharCode( 32, 55, 49, 45, 49, 68 ) );
var idBkCl = charIDToTypeID( "BkCl" );
desc9.putObject( idClr, idBkCl, desc10 );
var idSCch = charIDToTypeID( "SCch" );
desc8.putObject( idT, idSCch, desc9 );
executeAction( idsetd, desc8, DialogModes.NO );
はい、なんのこっちゃですね。
出力ファイルの中身はどうなっているの?
先達が色々調べて、考察した上で、サンプルを載せてくださっています。
わーいわーい!
Script to assign a Pantone color to a channel in photoshop
おや、ちょっと待ってください。
コメントアウトされている箇所があります。
/*
haven't observed any difference when those were left outvar idbookID = stringIDToTypeID( "bookID" );
desc3.putInteger( idbookID, 3060 );
*/
/*
the code seems to be in ASCII and represent a non-standard pantone IDvar idbookKey = stringIDToTypeID( "bookKey" );
desc3.putData( idbookKey, String.fromCharCode( 79, 82, 48, 50, 49, 67 ) );
*/
ふむ。
haven't observed any difference when those were left out
「それらが放棄されたときに何の違いも観察しなかった」 by google先生
the code seems to be in ASCII and represent a non-standard pantone ID
「コードはASCIIで、非標準のpantone IDを表しているようです」 by google先生
さらに、末尾のコメントにはこうあります。
Luckily, all seems well even without those lines.
「幸運にも、これらの行がなくてもすべてがうまくいくようです」 by google先生
本当になくても良いのか試してみた
その1 「 ANPA 」の「 ANPA 71-1 AdPro 」を指定してみる → ×
そして、チャネルに当たっているのはなぜかANPAですらなく、PANTONE。

その2 「 PANTONE solid coated 」の「 PANTONE YELLOW C 」を指定してみる → ×
一見、うまくいってそうに見えてうまくいっていないという、一番事故になるやつです。
「PANTONE solid coated」を指定したのに、「PANTONE+ Solid Coated」が割り当てられています。

その3 「 DIC Color 」の「 DIC 1s 」を指定してみる → ◯
結論
うまくいくのもあるが、うまくいかないのもある。
よって、ColorBookに紐づくIDと、特色名に紐づくIDが必要になる。
つまり先達のコードのままじゃダメじゃないですか、やだー。
カラーブックのデータから必要な情報を抜き出そう
私の環境の場合は、以下のパスに全26ファイルのカラーブックが存在します。
/Applications/Adobe Photoshop CC 2018/Presets/
先頭のファイルは、ANPA Color.acb
でした。
拡張子はacbです。
acbとは、Adobe Photoshop Color Book Fileのことらしいです。
完全にAdobeの独自ファイルじゃないですか、やだー。
acbファイルの仕様ってあるの?
ないです。
少なくとも私は発見できませんでした。
ただ、ファイルフォーマットをリバースエンジニアリングして、非公式の仕様にまとめてくださった偉大な先達がいます!
Adobe Color Book File Format Specification
しゅごい...でも、わからない!
と、諦めては進めないのでこの仕様書を頼りにNode.JSを使い、ビット演算とか駆使して、最終成果物としてjsonファイルを作りました。
[
{
"vendorID": 3000,
"title": "ANPA Color",
"colorList": [
{
"name": "71-1",
"displayName": "ANPA 71-1 AdPro",
"id": " 71-1D"
},
{
"name": "71-2",
"displayName": "ANPA 71-2 AdPro",
"id": " 71-2D"
},
{
"name": "71-4",
"displayName": "ANPA 71-4 AdPro",
"id": " 71-4D"
},
{
"name": "71-6",
"displayName": "ANPA 71-6 AdPro",
"id": " 71-6D"
},
{
"name": "71-8",
"displayName": "ANPA 71-8 AdPro",
"id": " 71-8D"
},
// 以下略
ExtendScriptを書こう
ここまできたら、あと少し。
とりあえず、特色を設定するところだけ抜粋して、実際に動くか試します。
以下の例では、ANPA Colorの先頭の特色を設定してみています。
/**
* 特色の設定
* @param colorBookName カラーブック名
* @param colorName 色名
* @param colorBookId カラーブックID
* @param colorId 特色名ID
*/
function setColor(
colorBookName: string,
colorName: string,
colorBookId: number,
colorId: string
) {
const idsetd = app.charIDToTypeID( "setd" );
const mainDesc = new ActionDescriptor();
const idnull = app.charIDToTypeID( "null" );
const ref = new ActionReference();
const idChnl = app.charIDToTypeID( "Chnl" );
const idOrdn = app.charIDToTypeID( "Ordn" );
const idTrgt = app.charIDToTypeID( "Trgt" );
ref.putEnumerated( idChnl, idOrdn, idTrgt );
mainDesc.putReference( idnull, ref );
const idT = app.charIDToTypeID( "T " );
// channel名をcolorNameで置換する?
// const idNm0 = app.charIDToTypeID("Nm ");
// mainDesc2.putString(idNm0, colorName);
// color
const idClr = app.charIDToTypeID( "Clr " );
const changeSpotColorDesc = new ActionDescriptor();
// set the color book to use
const idBk = app.charIDToTypeID( "Bk " );
changeSpotColorDesc.putString( idBk, colorBookName );
// set the color name
const idNm = app.charIDToTypeID( "Nm " );
changeSpotColorDesc.putString( idNm, colorName );
// Adobe独自のカラーブックに紐づくID
const idbookID = app.stringIDToTypeID( "bookID" );
changeSpotColorDesc.putInteger( idbookID, colorBookId );
// Adobe独自の特色に紐づく6文字固定サイズのID
const idbookKey = app.stringIDToTypeID( "bookKey" );
changeSpotColorDesc.putData( idbookKey, colorId );
// BkCl = BookColor;
const idBkCl = app.charIDToTypeID( "BkCl" );
const setColorChannelDesc = new ActionDescriptor();
setColorChannelDesc.putObject( idClr, idBkCl, changeSpotColorDesc );
// Opct = opacity
const idOpct = app.charIDToTypeID( "Opct" );
const idPrc = app.charIDToTypeID( "#Prc" );
setColorChannelDesc.putUnitDouble( idOpct, idPrc, 100 );
// SCch = SetColorChannel?
const idSCch = app.charIDToTypeID( "SCch" );
mainDesc.putObject( idT, idSCch, setColorChannelDesc );
// 実行
app.executeAction( idsetd, mainDesc, DialogModes.NO );
}
setColor("ANPA", "ANPA 71-1 AdPro", 3000, " 71-1D");
結果として、第一引数と第二引数はなくても動くんじゃなかろうか。
そして、第四引数の先頭にスペースがありますが、IDは6文字なので必須だと思います。
あとは、
- ユーザにどのチャネルの特色を設定したいか選ばせる
- 特色一覧を表示して、特色を選択させる
-
setColor
に値を渡す
でいけます。