Photoshopで漫画の2値原稿を作るScript
Photoshopだけで同人誌の原稿を作るというへそ曲がり
マイノリティの王道を行く、Photoshopだけで2値1200dpiの同人誌原稿を作るというおバカな作業をいまだにしているわたし。
手作業だと流石に大変なので、ここもJavascript使用で時短を求めました。
プログラムへたっぴだから、なおさら大変なのに。
このScriptのコードと内容を下記に残します。
ScriptListenerを多用しているので、あまり参考にはならないかもだけど。
あと、自分専用なので、エラー回避とか、なにそれおいしい?状態です。
工程動画
A5同人誌1200dpiグレースケールの原稿を作成し、貼りたいトーンごとにグループを作って、グレーで着色していきます。
出来上がった原稿に対して、2値化javascriptを実行するとグループごとに2値のトーンレイヤーを作成し、元のグループを非表示にします。
問題がないのを確認したら、手作業でレイヤーを統合して、2値データに変更して完成です。
スクリプトの構成
このscriptは、トーン化するグループ名ごとのscriptと、それを呼びだすscriptから構成されています。
親script:all.jsx(グループ名を判定して個別scritを呼び出す)
個別script:75ami.jsx(グループ名amiに対応する:75線アミ)
suna.jsx(グループ名sunaに対応する:砂目)
dither.jsx(グループ名ditherに対応する:点描)
30ami.jsx(グループ名30に対応する:30線のアミ)
40sima-yoko.jsx(グループ名yokojimaに対応する:横縞)
60sima-tate.jsx(グループ名tatejimaに対応する:縦縞)
75shiro-ami.jsx(グループ名suroamiに対応する:白の75線アミ)
sirodither.jsx(グループ名siroditherに対応する:白の点描)
sirosuna.jsx(グループ名sirosunaに対応する:ぢろの砂目)
all.jsxのなかみ
//https://note.com/akemi_hatsuno
//copyright 初野あけみ
//原稿ファイル
var genko = activeDocument;
//レイヤーセットの数を取得
var M =genko.layerSets.length;
//レイヤーセットの数だけ
//(グループ0からグループM-1まで)
//レイヤーセットの名前で判定してパターンをかえて2値化を繰り返す
//(ここで外部のjsxを使用)
//名前が当てはまらなければスルー
for (i=0; i<=M-1; i++)
{
//判定するレイヤーセットをアクティブにして
//レイヤーセットの名前をLに格納
//N =genko.layerSets[i];
genko.activeLayer=genko.layerSets[i];
var L=genko.layerSets[i].name;
switch(L)
{
case "ami":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/75ami.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
; break;
case "suna":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/suna.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "dither":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/dither.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "30":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/30ami.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "yokojima":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/40sima-yoko.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "tatejima":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/60sima-tate.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "siroami":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/75shiro-ami.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "sirodither":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/sirodither.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
case "sirosuna":
//格納したスクリプト名でトーン化スクリプトを呼び出す
var idAdobeScriptAutomationScripts = stringIDToTypeID( "AdobeScriptAutomation Scripts" );
var desc42 = new ActionDescriptor();
var idjsCt = charIDToTypeID( "jsCt" );
desc42.putPath( idjsCt, new File( "/Applications/Adobe Photoshop 2022/Presets/Scripts/1200dpi_2script/sirosuna.jsx" ) );
var idjsMs = charIDToTypeID( "jsMs" );
desc42.putString( idjsMs, genko );
executeAction( idAdobeScriptAutomationScripts, desc42, DialogModes.NO );
break;
default: ;
}
}
var idcollapseAllGroupsEvent = stringIDToTypeID( "collapseAllGroupsEvent" );
var desc1776 = new ActionDescriptor();
executeAction( idcollapseAllGroupsEvent, desc1776, DialogModes.NO );
var idcollapseAllGroupsEvent = stringIDToTypeID( "collapseAllGroupsEvent" );
var desc18 = new ActionDescriptor();
executeAction( idcollapseAllGroupsEvent, desc18, DialogModes.NO );
修正したい場合・自分ちで使ってみたい場合は、下記の赤字の①②を修正。
switchでグループ名で条件分岐して、個別スクリプトを呼び出しているので、
トーンの種類を増やしたい場合は、「case」から「;break;」までの10行をコピペして、①②を修正する。
Macで使用しているので、スクリプトの保存先が、アプリケーションのプリセット内になっています。
1200dpi_2scriptは今回のスクリプトをまとめたフォルダの名称。
個別script(アミ)
//https://note.com/akemi_hatsuno
//copyright 初野あけみ
//原稿ファイルとサイズ
var genko = activeDocument;
//現在レイヤー原稿サイズを取得
var layerSetRef = genko.activeLayer ;
var haba=activeDocument.width ;
var takasa=activeDocument.height ;
var genkodpi = activeDocument.resolution;
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
var idDcmn = charIDToTypeID( "Dcmn" );
ref2.putClass( idDcmn );
desc3.putReference( idnull, ref2 );
var idUsng = charIDToTypeID( "Usng" );
var ref3 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref3.putEnumerated( idLyr, idOrdn, idTrgt );
desc3.putReference( idUsng, ref3 );
var idVrsn = charIDToTypeID( "Vrsn" );
desc3.putInteger( idVrsn, 5 );
executeAction( idMk, desc3, DialogModes.NO );
// =======================================================
var tmpfile = activeDocument;
//一時ファイルのレイヤーを結合
app.activeDocument = tmpfile ;
tmpfile.mergeVisibleLayers();
//2値化の形状を指定
var opt = new BitmapConversionOptions()
//2値化オプション
//ハーフトーンスクリーン
//(ディザ=DIFFUSIONDITHER)
opt.method = BitmapConversionType.HALFTONESCREEN ;
//角度
opt.angle = 45 ;
//線数
opt.frequency = 75 ;
//2値解像度
opt.resolution = genkodpi ;
//パターンの形状
//円
//(線はLINE)
opt.shape = BitmapHalfToneType.ROUND ;
//2値化実行
tmpfile.changeMode(ChangeMode.BITMAP,opt) ;
//グレスケに戻す
tmpfile.changeMode(ChangeMode.GRAYSCALE) ;
//レイヤーを乗算にする
tmpfile.opacity = 100 ;
tmplayer = activeDocument.activeLayer ;
tmplayer.blendMode = BlendMode.MULTIPLY ;
//2値化レイヤーを元のファイルに複製
tmpfile.activeLayer.duplicate(layerSetRef,ElementPlacement.PLACEBEFORE);
//元のファイルをアクティブ
activeDocument = genko;
//元のレイヤーセットを非表示
layerSetRef.visible = false;
app.activeDocument =tmpfile;
//新規ファイルを破棄
tmpfile.close(SaveOptions.DONOTSAVECHANGES);
//元のファイルをアクティブ
activeDocument = genko;
アミの線数や角度を変更したいときは、下記の①②を変更する。
点描script(ditherで2値化)
//https://note.com/akemi_hatsuno
//copyright 初野あけみ
// 単位系を保存して変更
var strtRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
//原稿ファイルとサイズ
var genko = activeDocument;
//現在レイヤー原稿サイズを取得
var layerSetRef = genko.activeLayer ;
var haba=activeDocument.width ;
var takasa=activeDocument.height ;
var genkodpi = activeDocument.resolution;
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
var idDcmn = charIDToTypeID( "Dcmn" );
ref2.putClass( idDcmn );
desc3.putReference( idnull, ref2 );
var idUsng = charIDToTypeID( "Usng" );
var ref3 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref3.putEnumerated( idLyr, idOrdn, idTrgt );
desc3.putReference( idUsng, ref3 );
var idVrsn = charIDToTypeID( "Vrsn" );
desc3.putInteger( idVrsn, 5 );
executeAction( idMk, desc3, DialogModes.NO );
// =======================================================
var tmpfile = activeDocument;
//一時ファイルのレイヤーを結合
app.activeDocument = tmpfile ;
tmpfile.mergeVisibleLayers();
//2値化の形状を指定
var opt = new BitmapConversionOptions()
//2値化オプション
opt.method = BitmapConversionType.DIFFUSIONDITHER ;
//2値解像度
opt.resolution = 300 ;
//2値化実行
tmpfile.changeMode(ChangeMode.BITMAP,opt) ;
var tmpdpi = opt.resolution ;
//グレスケに戻す
tmpfile.changeMode(ChangeMode.GRAYSCALE) ;
//レイヤーを乗算にする
tmpfile.opacity =100;
tmplayer = activeDocument.activeLayer ;
tmplayer.blendMode = BlendMode.MULTIPLY ;
//一時ファイルの幅と高さ取得
//解像度を元に戻すが、幅、高さを(元ファイル解像度/一時ファイル解像度)の倍数になるようにする
haba2=activeDocument.width ;
takasa2=activeDocument.height ;
//(元ファイル解像度/一時ファイル解像度)
bairitsu=genkodpi/tmpdpi;
haba2=haba2*bairitsu;
takasa2=takasa2*bairitsu;
//原稿の解像度に戻す
tmpfile.resizeImage(haba2,takasa2,genkodpi,ResampleMethod.NEARESTNEIGHBOR);
//原稿のファイルと同じカンバスサイズに切り捨て(もしくは増加)
tmpfile.resizeCanvas(haba,takasa,AnchorPosition.MIDDLECENTER);
//2値化レイヤーを元のファイルに複製
tmpfile.activeLayer.duplicate(layerSetRef,ElementPlacement.PLACEBEFORE);
//元のファイルをアクティブ
activeDocument = genko;
//元のレイヤーセットを非表示
layerSetRef.visible = false;
app.activeDocument =tmpfile;
//新規ファイルを破棄
tmpfile.close(SaveOptions.DONOTSAVECHANGES);
//元のファイルをアクティブ
activeDocument = genko;
// 単位系を元に戻して終了=====================================================
preferences.rulerUnits = strtRulerUnits;
2値化の誤差拡散法(ディザ)を利用して点描のトーンを作ります。
ただ、単純にディザにすると、1px x 1pxの点の集合ができてしまい、印刷に出なくなるので、1200dpiから300dpiに変更してディザデータを作ります。
その後、1200dpiにニアレストネイバーで戻すと4px x 4pxの点描の集合体が出来上がります。
もう少し大きい点が欲しいときは、①の300(dpi)を200や150にすればいいかと。
ただし、1200で割り切れる数字に。
元の原稿が600dpiの場合は同じ考え方で数字を調整してください。
点描系の場合だけ、最初と最後に単位系をpxにして戻す作業を追加してます。
解像度を変更する作業があるので。
個別script(カスタムパターン)
//https://note.com/akemi_hatsuno
//copyright 初野あけみ
//原稿ファイルとサイズ
var genko = activeDocument;
//現在レイヤー原稿サイズを取得
var layerSetRef = genko.activeLayer ;
var haba=genko.width ;
var takasa=genko.height ;
var genkodpi = genko.resolution;
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
var idDcmn = charIDToTypeID( "Dcmn" );
ref2.putClass( idDcmn );
desc3.putReference( idnull, ref2 );
var idUsng = charIDToTypeID( "Usng" );
var ref3 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref3.putEnumerated( idLyr, idOrdn, idTrgt );
desc3.putReference( idUsng, ref3 );
var idVrsn = charIDToTypeID( "Vrsn" );
desc3.putInteger( idVrsn, 5 );
executeAction( idMk, desc3, DialogModes.NO );
// =======================================================
var tmpfile = activeDocument;
//一時ファイルのレイヤーを結合
app.activeDocument =tmpfile;
tmpfile.mergeVisibleLayers();
//2値化の形状を指定
var opt = new BitmapConversionOptions()
//2値化オプション
//ハーフトーンスクリーン
//(ディザ=DIFFUSIONDITHER)
opt.method = BitmapConversionType.CUSTOMPATTERN ;
//角度
opt.patternName = "sunaS" ;
//2値解像度
opt.resolution = genkodpi ;
//パターンの形状
//円
//2値化実行
tmpfile.changeMode(ChangeMode.BITMAP,opt) ;
//グレスケに戻す
tmpfile.changeMode(ChangeMode.GRAYSCALE) ;
//レイヤーを乗算にする
tmpfile.opacity = 100 ;
tmplayer = tmpfile.activeLayer ;
tmplayer.blendMode = BlendMode.MULTIPLY ;
//2値化レイヤーを元のファイルに複製
tmplayer.duplicate(layerSetRef,ElementPlacement.PLACEBEFORE);
//元のファイルをアクティブ
app.activeDocument = genko;
//元のレイヤーセットを非表示
layerSetRef.visible = false;
app.activeDocument =tmpfile;
//新規ファイルを破棄
tmpfile.close(SaveOptions.DONOTSAVECHANGES);
//元のファイルをアクティブ
app.activeDocument = genko;
砂目は事前に塗りつぶしのパターンを定義しておき、その名前を指定したカスタムパターンの2値化を実行。
パターン定義用の画像は著作権に引っかかるので、ここに挙げられませんが、photoshopについてくるパターンなどをうまく利用してください。
(Adobeに昔確認したところ、塗りつぶし用のパターンは商用に利用できると言ってたはず)
カスタムパターンを変更する場合は下記の画像の①を変更する。
個別Script(白いアミ)
//https://note.com/akemi_hatsuno
//copyright 初野あけみ
//原稿ファイルとサイズ
var genko = activeDocument;
//現在レイヤー原稿サイズを取得
var layerSetRef = genko.activeLayer ;
var haba=activeDocument.width ;
var takasa=activeDocument.height ;
var genkodpi = activeDocument.resolution;
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
var idDcmn = charIDToTypeID( "Dcmn" );
ref2.putClass( idDcmn );
desc3.putReference( idnull, ref2 );
var idUsng = charIDToTypeID( "Usng" );
var ref3 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref3.putEnumerated( idLyr, idOrdn, idTrgt );
desc3.putReference( idUsng, ref3 );
var idVrsn = charIDToTypeID( "Vrsn" );
desc3.putInteger( idVrsn, 5 );
executeAction( idMk, desc3, DialogModes.NO );
// =======================================================
var tmpfile = activeDocument;
//一時ファイルのレイヤーを結合
tmpfile.mergeVisibleLayers();
//階調を反転(レイヤーを統合したとき背景の白と一緒になってしまうのをさけるため)
tmpfile.activeLayer.invert() ;
//2値化の形状を指定
var opt = new BitmapConversionOptions()
//2値化オプション
//ハーフトーンスクリーン
//(ディザ=DIFFUSIONDITHER)
opt.method = BitmapConversionType.HALFTONESCREEN ;
//角度
opt.angle = 45 ;
//線数
opt.frequency = 75 ;
//2値解像度
opt.resolution = genkodpi ;
//パターンの形状
//円
//(線はLINE)
opt.shape = BitmapHalfToneType.ROUND ;
//2値化実行
tmpfile.changeMode(ChangeMode.BITMAP,opt) ;
//グレスケに戻す
tmpfile.changeMode(ChangeMode.GRAYSCALE) ;
//階調を反転(元に戻す)黒を範囲指定して削除
tmpfile.activeLayer.invert() ;
// ここから色域指定=======================================================
var idClrR = charIDToTypeID( "ClrR" );
var desc3 = new ActionDescriptor();
var idClrs = charIDToTypeID( "Clrs" );
var idClrs = charIDToTypeID( "Clrs" );
var idShdw = charIDToTypeID( "Shdw" );
desc3.putEnumerated( idClrs, idClrs, idShdw );
var idcolorModel = stringIDToTypeID( "colorModel" );
desc3.putInteger( idcolorModel, 0 );
executeAction( idClrR, desc3, DialogModes.NO );
//ここまで色域指定=======================================================
//背景をレイヤーに変更
tmpfile.activeLayer.opacity = 100 ;
//選択範囲をクリア(透明に)
tmpfile.selection.clear() ;
//選択範囲解除
tmpfile.selection.deselect() ;
//2値化レイヤーを元のファイルに複製
tmpfile.activeLayer.duplicate(layerSetRef,ElementPlacement.PLACEBEFORE);
//元のファイルをアクティブ
activeDocument = genko;
//元のレイヤーセットを非表示
layerSetRef.visible = false;
app.activeDocument =tmpfile;
//新規ファイルを破棄
tmpfile.close(SaveOptions.DONOTSAVECHANGES);
塗りつぶしの上に、白のアミを被せたい場合のトーン。
通常のアミと同様に一時ファイルに複製した後、
白黒を反転してから、2値化を実行。
その後再度白黒反転させて、元の原稿に戻します。
線数、角度を変更したい場合は、通常のアミと同じところを変更します。
昔は手打ちでコードを書いていた
昔は、switchのところを、
L="ami": photoshop12.executeScript(ami80); break;
みたいにexcuteScriptを使って実行してたんですが、フォトショのバージョン上がるたびにphotoshop12の「12」を書き直さないといけなくて、さらにどこかのタイミングで使えなくなった記憶があります。
で、結果として、ScriptListenerを使用した長ったらしいコードになりました。
新規ファイルにグループを複製するのもエラーがでがちで、それも常にエラーになるわけではなくて、そこそこ動いているから何が悪いのか余計わからなくて、ここもScriptListerner……。
実際に使うときには
実際に使うときには、ダウンロードしたファイルを、適当な場所に保存して、all.jsxのなかの個別scriptのパスを書き換えてください。
Macの場合、アプリケーションのプリセットの中のscriptフォルダが妥当かと思います。
一度試しにscriptを実行して、それをアクションに登録しておくと、バッチで複数枚の原稿を一度にトーン化できるので便利です。
(このときプリセット以外のフォルダにscriptを保存していると、アクション実行時にセキュリティの都合なのか、scriptが見つからないと怒られます)
カスタムパターンでのトーン化を使用する場合は、事前に塗りつぶしのパターン定義で登録しておく必要があります。
zipにはダミーの.patファイルを入れています。テスト用にどうぞ。
あ、最近のphotoshopはパターンをフォルダに入れて階層化できるようになってるから、階層が違うと見つからないと怒られるかも。
↓こんな感じで保存してください。
電子書籍用の原稿を作るときには
電子書籍の原稿はピクセル数が少ないので、このスクリプトのアミ系の個別スクリプトだけ削除してグレスケにしたままのを元にjpg化してe-Pub作ってます。
そのうち、お手製e-Pub同人誌の作り方もアップします。
最後に
頑張ったから褒めて!
この記事が気に入ったらサポートをしてみませんか?