Photoshopでメタリックなテクスチャの制作方法を知りました。
が、キャンパスサイズによって感じがだいぶ変わってしまうので調度良いサイズを得るために何度か作り直していました。
これが徐々に面倒になりスクリプト化しようと思い立ち、何とか完成に。
テクスチャ製作手順
この本に載ってます。本をみなくても下に記述したスクリプトに記述してます。
翔泳社
売り上げランキング: 44876
スクリプト製作でやったこと
- Photoshop上の操作をスクリプトに出力
- スクリプトを解析
- なんとなく抽象化
Photoshop上の操作をスクリプトに出力
Photoshopに”ScriptingListener.plugin”というプラグインを入れます。(Mac)
プラグイン(adobe)
インストール方法も日本語で提供されてます。
このプラグインを入れている間は、デスクトップ上に”ScriptingListenerJS.log”というログファイルが出力されます。
開くとConsoleが立ち上がり中身を表示してくれます。
ただし、プラグインが入っている間はずっとログを出力しつづけるのでファイルが肥大化します。
気づかない間に容量を圧迫しているなんてことがないように、不要な時はプラグインを削除します。
スクリプトを解析
やりた処理がわからない時はPhotoshop上で操作をし、それをLog上から解析することでスクリプトの記述方法がわかります。
解析には次の公式ドキュメントが助けになりました。
ADOBE PHOTOSHOP CS6 JAVASCRIPT SCRIPTING REFERENCE
ポイントになるのは以下の2点です。
ActionDescriptor
何をするにも登場します。
このオブジェクトに色々な情報を付加し、特定の操作を定義します。
形式はDictionaryで、keyとValueで格納します。
特徴は、情報をKeyと値セットで保持します。
保持の際にデータ型をメソッド名を以て指定します。
function addBlur(angle,pix) { var idMtnB = charIDToTypeID( "MtnB" ); var desc170 = new ActionDescriptor(); var idAngl = charIDToTypeID( "Angl" ); desc170.putInteger( idAngl, angle ); var idDstn = charIDToTypeID( "Dstn" ); var idPxl = charIDToTypeID( "#Pxl" ); desc170.putUnitDouble( idDstn, idPxl, pix ); executeAction( idMtnB, desc170, DialogModes.NO ); }
こんな感じで入れ子になって各操作や数値が定義されます。
また、”MtnB”等の4文字KeyはAdobe側で定義されているのですが、先のドキュメントに載ってないものばかり吐出されるので、どうにかして欲しいところです。
ここは気合いで。
ActionList
このオブジェクトはデータが時系列的に平行して存在する場合にまとめて定義します。
グラデーションの色データ等を格納するのに使います。
なんとなく抽象化
ログを解析すると似た様な箇所がけっこう出て来るので抽象化すると、構造の理解が深まって幸せになれます。
次に出来上がったものを示します。
サンプル
以下のスクリプトをUTF8形式のテキストファイルに貼付けて、”xxx.jsx”という名前で保存します。
Photoshop上からFile > Script > Browse…で保存したファイルを指定すると実行されます。
//create metalic texture //Gradient var width = activeDocument.width; var height = activeDocument.height; var startP = new pos(width,0); var endP = new pos(0,height); gradient(startP,endP); //Noise addNoise(15.0, true, true); //Blur //これくらいが調度良かった。 addBlur(0,width/20); //Mono hueAndSaturation(0,-100,0); //data boj function pos(arg_x,arg_y){ this.x = arg_x; this.y = arg_y; } function hueAndSaturation(hue,saturation,lightness) { //hue / saturation var idHStr = charIDToTypeID( "HStr" ); var desc = new ActionDescriptor(); var idpresetKind = stringIDToTypeID( "presetKind" ); var idpresetKindType = stringIDToTypeID( "presetKindType" ); var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" ); desc.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom ); var idClrz = charIDToTypeID( "Clrz" ); //Colorize (色彩の統一) desc.putBoolean( idClrz, false ); var idAdjs = charIDToTypeID( "Adjs" ); var list10 = new ActionList(); var desc175 = new ActionDescriptor(); var idH = charIDToTypeID( "H " ); desc175.putInteger( idH, hue ); var idStrt = charIDToTypeID( "Strt" ); desc175.putInteger( idStrt, saturation ); var idLght = charIDToTypeID( "Lght" ); desc175.putInteger( idLght, lightness ); var idHsttwo = charIDToTypeID( "Hst2" ); list10.putObject( idHsttwo, desc175 ); desc.putList( idAdjs, list10 ); executeAction( idHStr, desc, DialogModes.NO ); } function addBlur(angle,pix) { var idMtnB = charIDToTypeID( "MtnB" ); var desc170 = new ActionDescriptor(); var idAngl = charIDToTypeID( "Angl" ); desc170.putInteger( idAngl, angle ); var idDstn = charIDToTypeID( "Dstn" ); var idPxl = charIDToTypeID( "#Pxl" ); desc170.putUnitDouble( idDstn, idPxl, pix ); executeAction( idMtnB, desc170, DialogModes.NO ); } function addNoise( p,isGsn,isMono ) { var idAdNs = charIDToTypeID( "AdNs" ); var noisDesc = new ActionDescriptor(); var gaussId; if(isGsn) { gaussId = charIDToTypeID( "Gsn " ); }else{ gaussId = charIDToTypeID( "Unfr" ); } var idDstr = charIDToTypeID( "Dstr" ); noisDesc.putEnumerated( idDstr, idDstr, gaussId ); var idNose = charIDToTypeID( "Nose" ); var idPrc = charIDToTypeID( "#Prc" ); //15% noisDesc.putUnitDouble( idNose, idPrc, p ); var idMnch = charIDToTypeID( "Mnch" ); noisDesc.putBoolean( idMnch, isMono ); var idFlRs = charIDToTypeID( "FlRs" ); noisDesc.putInteger( idFlRs, 5450347 ); executeAction( idAdNs, noisDesc, DialogModes.NO ); } function gradient(stratP,endP) { //各種情報入れとく場所 var master = new ActionDescriptor(); putStartPosition (master, startP.x, startP.y); putEndPosition (master, endP.x, endP.y); //終点 //Enumerated var idType = charIDToTypeID( "Type" ); var idGrdT = charIDToTypeID( "GrdT" ); var idLnr = charIDToTypeID( "Lnr " ); master.putEnumerated( idType, idGrdT, idLnr ); //Dthr var idDthr = charIDToTypeID( "Dthr" ); master.putBoolean( idDthr, true ); var idUsMs = charIDToTypeID( "UsMs" ); master.putBoolean( idUsMs, true ); var idGrad = charIDToTypeID( "Grad" ); var idNm = charIDToTypeID( "Nm " ); var desc12 = new ActionDescriptor(); //Asset gradient desc12.putString( idNm, """$$$/DefaultGradient/Copper=Copper""" ); var idGrdF = charIDToTypeID( "GrdF" ); var idCstS = charIDToTypeID( "CstS" ); desc12.putEnumerated( idGrdF, idGrdF, idCstS ); var idIntr = charIDToTypeID( "Intr" ); desc12.putDouble( idIntr, 4096.000000 ); var idClrs = charIDToTypeID( "Clrs" ); //最初の色データオブジェクト var list2 = new ActionList(); //RGBColorオブジェクト var colorObj1 = createRGBColorObj (151.000006, 70.000003, 26.000000); var desc13 = createRGBColorData(colorObj1,0,50); var idClrt = charIDToTypeID( "Clrt" ); list2.putObject( idClrt, desc13 ); //HSBColorオブジェクト /**/ var colorObj2 = createHSBColorObj(21.115723,21.568627,98.431373); var desc15 = createHSBColorData(colorObj2, 1229, 50); list2.putObject( idClrt, desc15 ); //色オブジェクト var colorObj3 = createRGBColorObj(108,46,22); var desc17 = createRGBColorData(colorObj3,3400,50); list2.putObject( idClrt, desc17 ); //色オブジェクト var colorObj4 = createRGBColorObj(239,219,205); var desc19 = createRGBColorData(colorObj4,4096,50); list2.putObject( idClrt, desc19 ); desc12.putList( idClrs, list2 ); //終了用リスト var list3 = new ActionList(); var desc21 = new ActionDescriptor(); putOpt (desc21, 100); putLctn (desc21, 0); putMdpn (desc21, 50) var idTrnS = charIDToTypeID( "TrnS" ); list3.putObject( idTrnS, desc21 ); var desc22 = new ActionDescriptor(); putOpt(desc22,100.0); putLctn (desc22, 4096); putMdpn (desc22, 50); var idTrnS = charIDToTypeID( "TrnS" ); list3.putObject( idTrnS, desc22 ); var idTrns = charIDToTypeID( "Trns" ); desc12.putList( idTrns, list3 ); var idGrdn = charIDToTypeID( "Grdn" ); master.putObject( idGrad, idGrdn, desc12 ); //実行 executeAction( idGrdn, master, DialogModes.NO ); } function putOpt(targetObj,Double) { var idOpct = charIDToTypeID( "Opct" ); var idPrc = charIDToTypeID( "#Prc" ); targetObj.putUnitDouble( idOpct ,idPrc ,Double ); } function putLctn(targetObj,Integer) { var idLctn = charIDToTypeID( "Lctn" ); targetObj.putInteger( idLctn, Integer ); } function putMdpn(targetObj,Integer) { var idMdpn = charIDToTypeID( "Mdpn" ); targetObj.putInteger( idMdpn, Integer ); } function createPositionDescriptor(x,y) { var desc = new ActionDescriptor(); var idHrzn = charIDToTypeID( "Hrzn" ); var idRlt = charIDToTypeID( "#Rlt" ); desc.putUnitDouble( idHrzn, idRlt, x );//key, unitID, value var idVrtc = charIDToTypeID( "Vrtc" ); var idRlt = charIDToTypeID( "#Rlt" ); desc.putUnitDouble( idVrtc, idRlt, y); return desc; } function putStartPosition(obj,x,y) { var pos = createPositionDescriptor(x,y); //開始位置のKey var idFrom = charIDToTypeID( "From" ); //開始位置のunitID var idPnt = charIDToTypeID( "Pnt " ); //開始位置オブジェクトをグラデーション実行オブジェクトに代入 obj.putObject( idFrom, idPnt, pos ); } function putEndPosition(obj,x,y) { var pos = createPositionDescriptor(x,y); //開始位置のKey var idFrom = charIDToTypeID( "T " ); //開始位置のunitID var idPnt = charIDToTypeID( "Pnt " ); //開始位置オブジェクトをグラデーション実行オブジェクトに代入 obj.putObject( idFrom, idPnt, pos ); } function createDescriptorWithGradientString(gradient) { if(gradient == null) { //文字列型のデータを追加。"で囲ったプリセットのグラデーション gradient = """$$$/DefaultGradient/BlackWhite=Black, White"""; gradient = """$$$/DefaultGradient/Copper=Copper"""; } var desc= new ActionDescriptor(); var idNm = charIDToTypeID( "Nm " ); desc.putString( idNm, gradient ); return desc; } function createCMYKColorObj(c,m,y,k) { var desc = new ActionDescriptor(); var idCyn = charIDToTypeID( "Cyn " ); desc.putDouble( idCyn, c); var idMgnt = charIDToTypeID( "Mgnt" ); desc.putDouble( idMgnt, m ); var idYlw = charIDToTypeID( "Ylw " ); desc.putDouble( idYlw, y); var idBlck = charIDToTypeID( "Blck" ); desc.putDouble( idBlck, k); return desc; } function createCMYKColorData( colorObj, Lctn) { var targetObj = new ActionDescriptor(); var idClr = charIDToTypeID( "Clr " ); var idCMYC = charIDToTypeID( "CMYC" ); targetObj.putObject( idClr, idCMYC, colorObj ); var idType = charIDToTypeID( "Type" ); var idClry = charIDToTypeID( "Clry" ); var idUsrS = charIDToTypeID( "UsrS" ); targetObj.putEnumerated( idType, idClry, idUsrS ); var idLctn = charIDToTypeID( "Lctn" ); targetObj.putInteger( idLctn, Lctn ); var idMdpn = charIDToTypeID( "Mdpn" ); targetObj.putInteger( idMdpn, 50 ); return targetObj; } function createRGBColorObj(r,g,b) { var desc = new ActionDescriptor(); var idRd = charIDToTypeID( "Rd " ); desc.putDouble( idRd, r ); var idGrn = charIDToTypeID( "Grn " ); desc.putDouble( idGrn, g); var idBl = charIDToTypeID( "Bl " ); desc.putDouble( idBl, b); return desc; } function createRGBColorData(colorObj,Lctn,Mdpn) { var desc = new ActionDescriptor(); var idClr = charIDToTypeID( "Clr " ); var idRGBC = charIDToTypeID( "RGBC" ); desc.putObject( idClr, idRGBC, colorObj ); var idType = charIDToTypeID( "Type" ); var idClry = charIDToTypeID( "Clry" ); var idUsrS = charIDToTypeID( "UsrS" ); desc.putEnumerated( idType, idClry, idUsrS ); putLctn (desc, Lctn); putMdpn (desc, Mdpn); return desc; } function createHSBColorObj(h,s,b) { var desc = new ActionDescriptor(); var idH = charIDToTypeID( "H " ); var idAng = charIDToTypeID( "#Ang" ); desc.putUnitDouble( idH, idAng, h); var idStrt = charIDToTypeID( "Strt" ); desc.putDouble( idStrt, s ); var idBrgh = charIDToTypeID( "Brgh" ); desc.putDouble( idBrgh, b); return desc; } function createHSBColorData(HSBObj,Lctn,Mdpn) { var desc = new ActionDescriptor(); var idClr = charIDToTypeID( "Clr " ); var idHSBC = charIDToTypeID( "HSBC" ); desc.putObject( idClr, idHSBC, HSBObj ); var idType = charIDToTypeID( "Type" ); var idClry = charIDToTypeID( "Clry" ); var idUsrS = charIDToTypeID( "UsrS" ); desc.putEnumerated( idType, idClry, idUsrS ); putLctn(desc,Lctn); putMdpn (desc, Mdpn); return desc; } function blackGradient() { //グラデーションを実行するオブジェクトを生成 var master = new ActionDescriptor(); putStartPosition(master,0.0,0.0); putEndPosition (master, 600, 0.0); var idType = charIDToTypeID( "Type" ); var idGrdT = charIDToTypeID( "GrdT" ); var idLnr = charIDToTypeID( "Lnr " ); master.putEnumerated( idType, idGrdT, idLnr ); var idDthr = charIDToTypeID( "Dthr" ); master.putBoolean( idDthr, true ); var idUsMs = charIDToTypeID( "UsMs" ); master.putBoolean( idUsMs, true );//bool 型のデータを追加 //ここからGradient Data var gradientData = createDescriptorWithGradientString(); //new ActionDescriptor(); var idIntr = charIDToTypeID( "Intr" ); gradientData.putDouble( idIntr, 4096.000000 ); //gradientData.putDouble( idIntr, 0.000000 ); // var colorList = new ActionList(); //black color obj var black = createCMYKColorObj(75.02,68.01,67,90.19); var colorData1 = createCMYKColorData(black,0); var idClrt = charIDToTypeID( "Clrt" ); colorList.putObject( idClrt, colorData1 ); var white = createCMYKColorObj(0,0,0,0); var colorData2 = createCMYKColorData(white,4096); colorList.putObject( idClrt, colorData2 ); var idClrs = charIDToTypeID( "Clrs" ); gradientData.putList( idClrs, colorList ); var list5 = new ActionList(); var desc34 = new ActionDescriptor(); putOpt(desc34,100.0); putLctn(desc34,0); putMdpn(desc34,50); var idTrnS = charIDToTypeID( "TrnS" ); list5.putObject( idTrnS, desc34 ); var desc35 = new ActionDescriptor(); putOpt(desc35,100.0); putLctn (desc35, 4096); putMdpn (desc35, 50); var idTrnS = charIDToTypeID( "TrnS" ); list5.putObject( idTrnS, desc35 ); var idTrns = charIDToTypeID( "Trns" ); gradientData.putList( idTrns, list5 ); var idGrad = charIDToTypeID( "Grad" );//key var idGrdn = charIDToTypeID( "Grdn" );//unitID master.putObject( idGrad, idGrdn, gradientData ); executeAction( idGrdn, master, DialogModes.NO ); }
応用
色オブジェクト(次のサンプル部分)をgradient()に追加して複雑なグラデーションを作成してみると面白いかもしれません。
//色オブジェクト var colorObj3 = createRGBColorObj(108,46,22);//createRGBColorObj(r,g,b); var desc17 = createRGBColorData(colorObj3,3400,50); list2.putObject( idClrt, desc17 );