PhotoshopでPSDを開いて合成画像を出力する場合は、入力フォルダーを列挙し、各PSDを開く・書き出す・元PSDを保存せず閉じる処理をJSXで組み合わせます。保存先と形式、縮小の条件を先に決めると、出力結果を照合できます。
この処理はPSDごとに1枚の画像を作る用途です。レイヤー単位はレイヤーを個別ファイルに書き出す方法、カンプ単位はレイヤーカンプの書き出しを使います。Photoshopを使わず階層内の保存済み合成画像を変換する方法は、ImageMagickの記事で説明しています。
入力と出力を先に決める
作業用にPSDを複製し、入力用と出力用のフォルダーを分けます。最初は2〜3ファイルで確認し、RGB・8bit、透明な部分があるPSD、縮小が必要な縦長・横長のPSDを含めます。既にPhotoshopで開いているPSDは、この例では処理対象から外します。
| 設定 | この例の処理 |
|---|---|
| 対象 | 選択フォルダー直下の .psd。拡張子の大文字も含む |
| 出力 | 各PSDの合成画像をPNGまたはJPEGにする |
| 保存先 | 入力と別のフォルダー。サブフォルダーの再帰処理はしない |
| 同じ名前の画像 | 既存の出力を見つけたファイルはスキップする |
| 開いているPSD | ファイルのパスを照合してスキップする |
| 色・ビット深度 | RGB・8bitのみ。自動で色モードやビット深度を変更しない |
| 縮小 | 上限を指定したときだけ長辺を縮小し、縦横比を維持する |
出力フォルダーはこの処理専用にします。書き出し直前にも存在を確認しますが、他のプログラムによる同時書き込みまで防ぐ仕組みではありません。ファイル名の大文字・小文字やフォルダーへの別名参照がある場合も、複製した入力で確認してください。
実行するファイル名と設定
下のコードを CGM_ExportFolderReview.jsx として保存し、先頭の2項目を編集します。初回は OUTPUT_FORMAT = "PNG"、MAX_LONG_EDGE = 0 のまま試します。
| 設定値 | 意味 |
|---|---|
OUTPUT_FORMAT = "PNG" |
PNG-24と透明度を指定する |
OUTPUT_FORMAT = "JPEG" |
JPEG、品質100を指定する。透明度は保持しない |
MAX_LONG_EDGE = 0 |
元の寸法を維持する |
MAX_LONG_EDGE = 1000 |
長辺が1000pxを超える画像だけ縮小する |
コードはICCプロファイルの埋め込みを指定していますが、sRGBへの変換処理は含めていません。JPEGの透明部分の背景や色の見え方は、出力画像を開いて確認します。納品にsRGBや特定の背景色が必要な場合は、入力をその条件に整えてから試してください。
キャンセル・既存ファイル・失敗を扱うコード
今回のコードは制御の流れを見直した確認用の例です。Node.jsでPhotoshopの処理を模したテスト12項目を通しましたが、Photoshopでの書き出しはまだ実行していません。画像形式・透明度・ICC・実際の縮小結果を確認してから使用します。
#target photoshop
// PNG or JPEG. 0 keeps the size; 1000 limits the long edge to 1000 px.
var OUTPUT_FORMAT = "PNG";
var MAX_LONG_EDGE = 0;
(function () {
if (OUTPUT_FORMAT != "PNG" && OUTPUT_FORMAT != "JPEG") {
alert("OUTPUT_FORMAT must be PNG or JPEG."); return;
}
if (MAX_LONG_EDGE < 0 || !isFinite(MAX_LONG_EDGE)) {
alert("MAX_LONG_EDGE must be zero or positive."); return;
}
var source = Folder.selectDialog("Select the input PSD folder");
if (!source) return;
var destination = Folder.selectDialog("Select a separate output folder");
if (!destination) return;
function key(path) { return String(path).replace(/\\/g, "/").toLowerCase(); }
if (key(source.fsName) == key(destination.fsName)) {
alert("Use separate input and output folders."); return;
}
var files = source.getFiles(function (file) {
return file instanceof File && /\.psd$/i.test(file.name);
});
if (!files.length) { alert("No PSD files in this folder."); return; }
var originalActive = app.documents.length ? app.activeDocument : null;
var oldUnits = app.preferences.rulerUnits;
var oldDialogs = app.displayDialogs;
var completed = 0, skipped = 0, failed = 0, notes = [];
function isAlreadyOpen(file) {
for (var i = 0; i < app.documents.length; i++) {
try {
if (key(app.documents[i].fullName.fsName) == key(file.fsName)) return true;
} catch (unsavedDocument) {}
}
return false;
}
try {
app.preferences.rulerUnits = Units.PIXELS;
app.displayDialogs = DialogModes.NO;
for (var n = 0; n < files.length; n++) {
var input = files[n], document = null;
var base = File.decode(input.name).replace(/\.psd$/i, "");
var output = new File(destination.fsName + "/" + base +
(OUTPUT_FORMAT == "PNG" ? ".png" : ".jpg"));
if (output.exists || isAlreadyOpen(input)) {
skipped++; notes.push("SKIP: " + base + " (existing output or open PSD)");
continue;
}
try {
document = app.open(input);
if (document.mode != DocumentMode.RGB ||
document.bitsPerChannel != BitsPerChannelType.EIGHT) {
throw new Error("This example accepts RGB/8-bit PSD only.");
}
var width = document.width.as("px"), height = document.height.as("px");
if (MAX_LONG_EDGE > 0 && Math.max(width, height) > MAX_LONG_EDGE) {
if (width >= height) {
document.resizeImage(UnitValue(MAX_LONG_EDGE, "px"), undefined,
undefined, ResampleMethod.BICUBIC);
} else {
document.resizeImage(undefined, UnitValue(MAX_LONG_EDGE, "px"),
undefined, ResampleMethod.BICUBIC);
}
}
var options = new ExportOptionsSaveForWeb();
options.format = OUTPUT_FORMAT == "PNG" ? SaveDocumentType.PNG : SaveDocumentType.JPEG;
options.PNG8 = false;
options.transparency = OUTPUT_FORMAT == "PNG";
options.interlaced = false;
options.includeProfile = true;
options.quality = 100;
// Recheck immediately before export; use the folder for this process only.
if (output.exists) throw new Error("Output appeared during processing.");
document.exportDocument(output, ExportType.SAVEFORWEB, options);
if (!output.exists || output.length === 0) throw new Error("Output file was not confirmed.");
completed++; notes.push("OK: " + base);
} catch (error) {
failed++; notes.push("ERROR: " + base + " / " + error.message);
} finally {
if (document) {
try { document.close(SaveOptions.DONOTSAVECHANGES); }
catch (closeError) { notes.push("CLOSE ERROR: " + base + " / " + closeError.message); }
}
}
}
} finally {
app.preferences.rulerUnits = oldUnits;
app.displayDialogs = oldDialogs;
if (originalActive) {
try { app.activeDocument = originalActive; } catch (closedByUser) {}
}
}
alert("Output: " + completed + " / Skip: " + skipped + " / Error: " + failed +
"\n" + notes.join("\n"));
})();
入力または出力フォルダーの選択をキャンセルした場合は、画像を開く前に終了します。処理中に1ファイルでエラーが出ても次へ進み、開いたPSDは元ファイルを保存せず閉じる構成です。単位とダイアログ設定は最後に戻します。閉じる処理自体が失敗した場合は結果表示の CLOSE ERROR を確認し、開いたままのPSDを調べます。
出力数はファイルの存在とサイズが0より大きいことを確認した数です。画像の内容が正しいことを保証する数ではありません。エラー時に不完全な新規画像が残る場合は、結果表示と実ファイルを照合し、次の実行で既存ファイルとしてスキップされた理由を確認します。
Photoshopから実行する手順
- 作業中の画像を保存し、処理用に複製したPSD以外が書き換わらない状態を確認します。
- [ファイル]→[スクリプト]→[参照]から
CGM_ExportFolderReview.jsxを選びます。 - 入力用のPSDフォルダーを選び、続いて別の出力フォルダーを選びます。
- 最後の出力・スキップ・エラーの件数とファイル名を確認します。
- 出力画像を開き、形式、寸法、透明部分、背景、色、合成内容を確認します。
JSXの保存と初回実行はスクリプトを実行する方法、繰り返し使う場合の登録はメニューに表示する方法で説明しています。保存したファイル名と、実際に選ぶファイルを一致させます。
書き出せない・結果が違うとき
| 症状 | 確認すること |
|---|---|
| 何も出力されない | キャンセル、対象PSDの有無、直下か、既存出力、開いているPSD |
| RGB/8bitのエラー | 元PSDの色モードとビット深度。変換は複製したファイルで行う |
| PNGの色数や透明度が違う | PNG8 = false と透明度の指定、入力の透明部分、実際の出力 |
| JPEGの背景が変わる | JPEGは透明度を持たない。入力の背景と出力を照合する |
| 保存時に止まる | 書き込み権限、保存名、空き容量、エラーに表示されたPSD |
| 1000pxにならない | 上限以下の画像は拡大しない。幅ではなく長辺を制限している |
[Web用に保存]は、Adobe公式が案内する書き出し機能です。このJSXはその処理を呼び出すため、現在の画像モードや保存条件に左右されます。Adobe公式:Save for Webも確認してください。
旧コード・動画と今回の確認範囲
旧記事にはJPEG、PNG、縮小JPEGの3例と配置先のコードを掲載していました。原文は末尾の比較資料に残しています。旧説明にあった CGM_PSDtoJPGorPNG.jsx という選択画面を、3つの個別コードが実装しているわけではありません。今回の手順は保存するファイル名を統一し、出力形式は先頭の設定で指定します。
旧PNG例はPNG-8/PNG-24を明示しておらず、旧縮小例は単位の設定を戻していません。フォルダー選択後のキャンセル確認や、既存画像・途中失敗の扱いも不足していました。今回の例との違いを確認してから、旧記事に対応するGitHubのコードを使用してください。
旧記事の動画は過去の操作資料として保持しています。今回のコードをPhotoshop 27.10.0で実行した記録ではありません。2026年10月3日の確認は旧コードの全文比較、Adobeの保存・スクリプト資料、構文と制御のテストまでで、実機出力・撮影は残っています。
旧掲載コードの比較資料
旧コード・コマンド・出力例の原文です。今回の実行結果と区別して参照してください。
旧コード4ブロックを表示(原文・全例の現行版動作は未検証)
app.bringToFront();
main();
function main()
{
var folderObj = new Object();
var sourceFolder = Folder.selectDialog('フォルダを選択してください:', Folder(folderObj));
var docs = sourceFolder.getFiles("*.psd");
var fileArray = new Array();
var len = docs.length;
for (var i = 0; i < len; i++)
{
var doc = docs[i];
fileArray.push(doc);
}
for (var i = 0; i < fileArray.length; i++)
{
var doc = open(fileArray[i]);
var docName = doc.name;
if (docName.indexOf(".") != -1)
{
var basename = docName.match(/(.*)\.[^\.]+$/)[1]
} else
{
var basename = docName
}
exportJpg(doc, sourceFolder, basename + '.jpg');
doc.close(SaveOptions.DONOTSAVECHANGES);
}
}
function exportJpg(doc, folder, name)
{
var file = new File(folder.fsName + "/" + name);
var options = new ExportOptionsSaveForWeb();
options.format = SaveDocumentType.JPEG;
options.includeProfile = false;
options.interlaced = false;
options.optimized = true;
options.lossy = 0;
options.quality = 100;
doc.exportDocument(file, ExportType.SAVEFORWEB, options);
}app.bringToFront();
main();
function main()
{
var folderObj = new Object();
var sourceFolder = Folder.selectDialog('フォルダを選択してください:', Folder(folderObj));
var docs = sourceFolder.getFiles("*.psd");
var fileArray = new Array();
var len = docs.length;
for (var i = 0; i < len; i++)
{
var doc = docs[i];
fileArray.push(doc);
}
for (var i = 0; i < fileArray.length; i++)
{
var doc = open(fileArray[i]);
var docName = doc.name;
if (docName.indexOf(".") != -1)
{
var basename = docName.match(/(.*)\.[^\.]+$/)[1]
} else
{
var basename = docName
}
exportPng(doc, sourceFolder, basename + '.png');
doc.close(SaveOptions.DONOTSAVECHANGES);
}
}
function exportPng(doc, folder, name)
{
var file = new File(folder.fsName + "/" + name);
var options = new ExportOptionsSaveForWeb();
options.format = SaveDocumentType.PNG;
options.optimized = true;
options.interlaced = false;
doc.exportDocument(file, ExportType.SAVEFORWEB, options);
}app.bringToFront();
main();
function main() {
var folderObj = new Object();
var sourceFolder = Folder.selectDialog('フォルダを選択してください:', Folder(folderObj));
var docs = sourceFolder.getFiles("*.psd");
var fileArray = new Array();
var len = docs.length;
for (var i = 0; i < len; i++) {
var doc = docs[i];
fileArray.push(doc);
}
for (var i = 0; i < fileArray.length; i++) {
var doc = open(fileArray[i]);
var docName = doc.name;
if (docName.indexOf(".") != -1) {
var basename = docName.match(/(.*)\.[^\.]+$/)[1]
} else {
var basename = docName
}
doc.mergeVisibleLayers(); //表示レイヤーを結合
preferences.rulerUnits=Units.PIXELS; //単位をピクセルに
//幅1000pxより大きい場合は比率を維持しつつ幅1000pxに
if(doc.width>1000){
doc.resizeImage(1000, undefined, undefined, ResampleMethod.AUTOMATIC, 0);
}
//高さ1000pxより大きい場合は比率を維持しつつ高さ1000pxに
if(doc.height>1000){
doc.resizeImage(undefined, 1000, undefined, ResampleMethod.AUTOMATIC, 0);
}
exportJpg(doc, sourceFolder, basename + '.jpg');
doc.close(SaveOptions.DONOTSAVECHANGES);
}
}
function exportJpg(doc, folder, name) {
var file = new File(folder.fsName + "/" + name);
var options = new ExportOptionsSaveForWeb();
options.format = SaveDocumentType.JPEG;
options.includeProfile = false;
options.interlaced = false;
options.optimized = true;
options.lossy = 0;
options.quality = 100;
doc.exportDocument(file, ExportType.SAVEFORWEB, options);
}C:\Program Files\Adobe\Adobe Photoshop CC\Presets\Scripts\