動きます。動きますが、ロジックから書き直す予定。
Illustratorのバージョンによって、配置画像がどう扱われるかがだいぶ変わります。
2024ではJPEGは72ppi扱いされているため、このスクリプトではそのように扱いますが、2023では動作が変わるため、コードを変更しないと正しくサイズを取得できません。
バージョンアップしたときには、サンプルファイルを作って動作をテストすることをお勧めします。
Photoshopで開いている画像をIllustratorドキュメントから探し、matrixを用いて計算した横幅サイズに指定解像度でリサイズするAppleScriptです。
jsxで書こうとして、Illustratorのbridgetalkがめちゃくちゃ面倒だったため、BT要らないAppleScriptで、ChatGPT4oにアフィン変換のコード書かせて書きました。
- Photoshop側から実行し、ダイアログ類もPs側から出す
- ファイルタイプ、マスク状態、回転状態に依らず正しいサイズを取得できること(ここに穴がありそう)
- 拡大・縮小で処理を分岐する(縮小は古き良きバイキュービック、拡大はディテールを保持2.0(deepUpscale)を使用する
- 拡大率によって処理の停止を勧告する(scaleMax200%以上は保持2.0でもしんどいので他のAIリサンプルで処理したほうがいい。また微妙な拡縮は劣化するだけで無駄)
- 重ねがけしないよう、psのスナップショットに記録する(ヒストリーなのでファイル閉じれば消える)
1枚ずつ処理することを目的としています。
リサイズ処理は破壊的処理でもあり、モアレを作ってしまうとまずいこと
リサイズ後のシャープ処理は画像に最適化されてなければならないこと
以上の理由から、links一括処理は危険だと考えているため。
(*===================================
諸注意
Illustratorリンクの更新状態は見ていません。
リンク状態が正常であることをまず確認してから実行してください。
Photoshopの単位をpxに変更します(元の状態に戻しません)。
===================================*)
(*===================================
ターゲット解像度と、リサイズ限界値の変数設定
===================================*)
set newPPI to 350 -- 解像度設定
--Keyboard Maestroから実行する場合、解像度をVariableに入れておく。
--Keyboard Maestroを使わない場合は下の1行をコメントアウトする。
tell application "Keyboard Maestro Engine" to set newPPI to getvariable "targetPPI"
set scaleMax to 250 -- この倍率を超えたら処理の停止勧告
--この倍率以内なら処理の停止勧告(無駄な処理で劣化させないため)
set efScaleMax to 110
set efScaleMin to 90
(*===================================
Photoshopの処理
画像ファイルのパス名とピクセル幅を取得
Illustratorはjpeg/png/クリッピングパス付きPSDを72ppiと見なすため、
ファイル種別も判別する
===================================*)
tell application id "com.adobe.photoshop"
-- ドキュメントが開かれていなければ中止する
if (count of documents) is 0 then
display alert "⚠️開いているドキュメントがありません。"
return
end if
--スナップショットに"ResizeImagebyAS"があるなら中止する
if (do javascript "(function(){var myH=app.activeDocument.historyStates;for(i=0;i<myH.length;i++){if(myH[i].snapshot && myH[i].name=='ResizeImagebyAS'){return 1}}return 0;}())") = "1" then
display alert "⚠️実行済みです" & return & "再度実行する際は、" & return & "ヒストリーパネルのスナップショット" & return & "\"ResizeImagebyAS\"" & return & "を削除してください"
return
end if
set psDoc to current document
set ruler units of settings to pixel units
set pxW to width of psDoc
set pxH to height of psDoc
set psPPI to resolution of psDoc
set psPath to file path of psDoc as string
-- ファイルの種類を判定
if psPath ends with ".jpg" or psPath ends with ".jpeg" then
set fileType to "JPEG"
else if psPath ends with ".png" then
set fileType to "PNG"
else if psPath ends with ".psd" then
set fileType to "PSD"
else
set fileType to "OTHER"
end if
-- クリッピングパスが設定されているかを判定
if fileType is "PSD" then
set pathItems to path items of psDoc
set clippingFound to false
repeat with pItem in pathItems
if kind of pItem is clipping then
set clippingFound to true
exit repeat
end if
end repeat
else
set clippingFound to false
end if
end tell
(*===================================
Illustratorでパス名が同じものを拾い
matrixからサイズとscaleを取得
===================================*)
tell application id "com.adobe.illustrator"
-- ドキュメントが開かれていなければ中止する
if (count of documents) is 0 then
my PSMsg("⚠️Illustratorドキュメントが開かれていません。")
return
end if
set ilDoc to current document
set placedItems to every placed item of ilDoc
set matchItems to {}
-- 同じファイルパスの配置アイテムを探す
repeat with i in placedItems
if file path of i as string = psPath then
set end of matchItems to i
end if
end repeat
if (count of matchItems) is 0 then
my PSMsg("⚠️一致する配置アイテムが見つかりませんでした。")
return
end if
-- 最も大きく配置されているアイテムを探す
set largestItem to item 1 of matchItems
set maxScale to 0
repeat with pItem in matchItems
set matrixVals to matrix of pItem
set aVal to mvalue_a of matrixVals
set bVal to mvalue_b of matrixVals
set cVal to mvalue_c of matrixVals
set dVal to mvalue_d of matrixVals
-- スケールを計算
set scaleX to ((aVal * aVal) + (cVal * cVal)) ^ 0.5
set scaleY to ((bVal * bVal) + (dVal * dVal)) ^ 0.5
set curScale to scaleX * scaleY -- 現在のスケールを計算
if curScale > maxScale then
set maxScale to curScale -- 最大スケールを更新
set largestItem to pItem -- 最大スケールのアイテムを更新
end if
end repeat
-- 配置サイズを計算
set matrixVals to matrix of largestItem
set aVal to mvalue_a of matrixVals
set cVal to mvalue_c of matrixVals
-- ファイルタイプに応じた処理
if fileType is "JPEG" or fileType is "PNG" or (fileType is "PSD" and clippingFound) then
set actualPpi to 72
else
set actualPpi to psPPI
end if
set mmW to (pxW / actualPpi) * 25.4
set scaleX to ((aVal * aVal) + (cVal * cVal)) ^ 0.5
-- 配置サイズを計算
set placedW to mmW * scaleX
end tell
(*===================================
Photoshopリサイズ処理
===================================*)
tell application id "com.adobe.photoshop"
activate
set pxW_before to width of psDoc
set mmW_before to (pxW_before / psPPI) * 25.4
set pxW_after to (placedW / 25.4) * newPPI
set resizeScale to pxW_after / pxW_before
set scaleAlert to ""
-- 拡大率がscaleMaxを越える場合の確認
if (resizeScale * 100) > scaleMax then
set defaultBtn to "キャンセル"
set scaleAlert to "⚠️拡大率が" & (scaleMax as text) & "%を越えています。キャンセルしますか?"
else
if efScaleMin < resizeScale * 100 and resizeScale * 100 < efScaleMax then
set defaultBtn to "キャンセル"
set scaleAlert to (("⚠️拡大率が" & efScaleMin as text) & "%~" & efScaleMax as text) & "%程度です。" & return & "⚠️不要な劣化を避けるため、処理しないことをお勧めします。"
else
set defaultBtn to "実行"
end if
end if
set dialogMessage to (((((round (pxW_before * 10) / 10) as text) & " px(配置サイズ:" & (placedW + 0.05) div 0.1 / 10) as text) & "mm)" & return & ¬
"▼" & (round (resizeScale * 1000) / 10) as text) & "%" & return & ¬
((round (pxW_after * 10) / 10) as text) & " px(" & newPPI & "ppiで" & (placedW + 0.05) div 0.1 / 10 & "mm)" & return & scaleAlert
display dialog dialogMessage buttons {"キャンセル", "実行"} default button defaultBtn
if button returned of result is "キャンセル" then
return
end if
-- JavaScriptでリサイズ処理
if resizeScale < 1 then
-- 縮小処理
do javascript "var doc = app.activeDocument;
doc.resizeImage(UnitValue(" & pxW_after & ", 'px'), null, " & newPPI & ", ResampleMethod.BICUBIC);
"
else
-- 拡大処理
do javascript "var doc = app.activeDocument;
var desc = new ActionDescriptor();
desc.putUnitDouble(app.charIDToTypeID('Wdth'), app.charIDToTypeID('#Pxl'), " & pxW_after & ");
desc.putBoolean(app.stringIDToTypeID('scaleStyles'), true);
desc.putBoolean(app.stringIDToTypeID('constrainProportions'), true);
desc.putEnumerated(app.charIDToTypeID('Intr'), app.stringIDToTypeID('interpolationType'), app.stringIDToTypeID('deepUpscale'));
desc.putInteger(app.stringIDToTypeID('noise'), 10);
desc.putUnitDouble(app.charIDToTypeID('Rslt'), app.charIDToTypeID('#Rsl'), " & newPPI & ");executeAction(app.charIDToTypeID('ImgS'), desc, DialogModes.NO);
"
end if
-- ピクセル等倍表示
tell application "System Events" to keystroke "0" using {command down, option down}
--スナップショットに"ResizeImagebyAS"を作り、実行したことを記録する。
do javascript "var idMk=charIDToTypeID('Mk ');var desc7=new ActionDescriptor();var idnull=charIDToTypeID('null');var ref1=new ActionReference();var idSnpS=charIDToTypeID('SnpS');ref1.putClass(idSnpS); desc7.putReference(idnull,ref1);var idFrom=charIDToTypeID('From');var ref2=new ActionReference();var idHstS=charIDToTypeID('HstS');var idCrnH=charIDToTypeID('CrnH');ref2.putProperty(idHstS,idCrnH);desc7.putReference(idFrom,ref2);var idNm=charIDToTypeID('Nm ');desc7.putString(idNm,'''ResizeImagebyAS''');var idUsng=charIDToTypeID('Usng');var idHstS=charIDToTypeID('HstS');var idFllD=charIDToTypeID('FllD');desc7.putEnumerated(idUsng,idHstS,idFllD);executeAction(idMk,desc7,DialogModes.NO);"
end tell
(*===================================
関数
===================================*)
on PSMsg(DispMesg) -- InDesign側でなく、実行側のPsでアラートを出すための関数
tell application id "com.adobe.photoshop" to display alert DispMesg
end PSMsg