Amazon10/19まで!プライム感謝祭開催中!セール会場へ

Photoshop JSXの書き方とコード例|文書・レイヤー・ファイル・エラー処理

PhotoshopのExtendScript(.jsx)で、文書の有無、レイヤーの階層、名前の一致、テキスト型、ファイルの取消を確認する短いコード例です。コピーして全部を連結するコード集ではありません。各例を別ファイルへ保存し、変更する例は自作文書のコピーで確認します。

旧25コードは後半の参照資料へ保持しました。

2026年10月17日に、新しい例のうち5本を、Adobe Photoshop 2026(27.11.0)とWindows 11 Pro(10.0.26200)で、[ファイル]→[スクリプト]→[参照]から実行して確かめました。

確かめたのは、文書の有無、グループ内を再帰して名前を読む、名前が1件だけ一致したレイヤーを選ぶ、テキストレイヤーの色、実行中のファイルのパスの5本です。

最上位の名前、背景の解除、ファイルを選んで開く、文字列の長さの4本は、構文と模擬条件の検査だけで、Photoshopでは実行していません。

練習用の文書(テキストレイヤー1つと、2段に入れ子にしたグループ)はスクリプトで作ったため、その作り方は確認に含めていません。

UXPの.psjsとはAPIが異なるため、JSXとPSJSの違いも確認してください。

目次

短いコードを選ぶ前の確認

操作条件と文書への変更
文書名/レイヤー一覧読取のみ。背景解除・ラスタライズ・保存は不要。
レイヤー選択同じ名前が複数ある場合は停止。選択状態は変わるが保存はしない。
背景解除・文字色レイヤー情報を変更する。コピーで試し、確認後は元に戻すか保存せず閉じる。
ファイルを開く取消・存在・読込失敗を区別。文書が増えるため対象を再確認。
削除・統合・書き出し原本で試さず、出力・上書き・取消を扱う完成例を使う。

AdobeのJavaScript Scripting Reference 2020のDocument/ArtLayer/LayerSetと、JavaScript Tools GuideのFile/Folder・エラー・文字列を確認しています。公式の旧版仕様と、このPCの現行版での操作成功は分けて扱います。

文書の有無とエラーを確認する

即時関数は変数を関数内にまとめる書き方です。ドラッグ実行を有効にする必須の条件ではありません。try/catchは失敗を通知する仕組みで、途中の編集を取り消す機能ではありません。

#target photoshop
(function () {
    if (app.documents.length === 0) { alert("文書を開いてください。"); return; }
    try {
        var doc = app.activeDocument;
        alert("対象: " + doc.name);
    } catch (error) {
        alert("エラー: " + error.message + " / 行: " + error.line);
    }
}());

画像を開いていないホーム画面のまま[参照]から実行すると、「スクリプト警告」の窓に「文書を開いてください。」と表示されました。

Photoshopの「スクリプト警告」の窓に「文書を開いてください。」と表示された画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。画像を開いていない状態で、文書の有無を確かめる例を[ファイル]→[スクリプト]→[参照]から実行したときの窓(窓の部分だけ切り出し)。

練習用の文書を開いた状態で実行すると、同じ窓に「対象:」と文書名が表示されました。

どちらの場合もエラーの窓は出ず、文書は変わりませんでした。

最上位レイヤーの名前を読む

doc.layersは最上位のArtLayerとLayerSetを含みます。グループ内はこの例では読んでいません。旧例には末尾reと閉じ括弧の不足があり、構文・実行エラーにつながるため、新例に含めません。名前を読むための背景解除も不要です。

(function () {
    if (app.documents.length === 0) { return; }
    var layers = app.activeDocument.layers;
    var names = [];
    for (var i = 0; i < layers.length; i++) { names.push(layers[i].name); }
    alert(names.join("\n"));
}());

グループ内を再帰して名前を読む

グループ名も先に記録し、子レイヤーへ進みます。出力順はこの走査順です。階層パスに同名があれば同じ文字列になるため、固有IDや選択順を表す値には使いません。速度比較は測定していません。

(function () {
    if (app.documents.length === 0) { return; }
    var names = [];
    function visit(parent, prefix) {
        for (var i = 0; i < parent.layers.length; i++) {
            var layer = parent.layers[i];
            var path = prefix + layer.name;
            names.push(path);
            if (layer.typename === "LayerSet") { visit(layer, path + "/"); }
        }
    }
    visit(app.activeDocument, "");
    alert(names.join("\n"));
}());

下の画像は、グループAの中にグループBを入れた練習用の文書で実行した結果です。

Photoshopの「スクリプト警告」の窓に、グループの階層を含むレイヤー名が上から順に7行表示された画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。グループ内を再帰して名前を読む例を、2段のグループがある練習用の文書で実行した結果(窓の部分だけ切り出し)。

レイヤーパネルの上から順に読み、グループ名の直後に、その中のレイヤーが「グループA/グループB/子レイヤー」の形で並びました。

背景レイヤーも「背景」として最後に出ました。

実行の前後でヒストリーの数は変わらず、文書は変更されませんでした。

名前が1件だけ一致したレイヤーを選ぶ

CGM_targetを探す名前に変更します。0件または2件以上なら選択しません。layers.getByNameだけで同名やグループ内の対象を一律に選べると扱わず、範囲と一致件数を明示します。

(function () {
    if (app.documents.length === 0) { return; }
    var doc = app.activeDocument;
    var matches = [];
    function find(parent, name) {
        for (var i = 0; i < parent.layers.length; i++) {
            var layer = parent.layers[i];
            if (layer.name === name) { matches.push(layer); }
            if (layer.typename === "LayerSet") { find(layer, name); }
        }
    }
    find(doc, "CGM_target");
    if (matches.length !== 1) { alert("一致数: " + matches.length + "。選択を変えません。"); return; }
    doc.activeLayer = matches[0];
}());

グループAの中にだけ CGM_target がある文書で実行すると、グループの中の CGM_target が選択されました。

Photoshopのレイヤーパネルで、グループAの中のCGM_targetが選択されている画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。名前が1件だけ一致したレイヤーを選ぶ例を実行した後のレイヤーパネル(パネルの部分だけ切り出し)。

最上位にも同じ名前のレイヤーを足して実行すると、「一致数: 2。選択を変えません。」と表示され、選択は元の「見出し」レイヤーのままでした。

Photoshopの「スクリプト警告」の窓に「一致数: 2。選択を変えません。」と表示された画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。同じ名前のレイヤーが2つある文書で、名前で選ぶ例を実行したときの窓(窓の部分だけ切り出し)。

スクリプトで選択を変えても、ヒストリーの項目は増えませんでした。

背景レイヤーだけを通常レイヤーへ変える

この例は編集操作です。最背面のレイヤーを背景と推定せず、isBackgroundLayerがtrueのArtLayerだけを変更します。背景がない場合は任意の最背面レイヤーを変更しません。

(function () {
    if (app.documents.length === 0) { return; }
    var doc = app.activeDocument;
    for (var i = 0; i < doc.artLayers.length; i++) {
        if (doc.artLayers[i].isBackgroundLayer) {
            doc.artLayers[i].isBackgroundLayer = false;
            return;
        }
    }
    alert("背景レイヤーがないため変更しません。");
}());

選択したテキストレイヤーの色を変える

ArtLayerかつLayerKind.TEXTを確認してから文字色を設定します。通常レイヤーやグループにはtextItemを読ませません。複数の文字色を持つテキストの保持はこの例の目的に含めず、全体の色を変える操作としてコピーで確認します。

(function () {
    if (app.documents.length === 0) { return; }
    var layer = app.activeDocument.activeLayer;
    if (layer.typename !== "ArtLayer" || layer.kind !== LayerKind.TEXT) {
        alert("テキストレイヤーを選択してください。"); return;
    }
    var color = new SolidColor();
    color.rgb.red = 0; color.rgb.green = 255; color.rgb.blue = 0;
    layer.textItem.color = color;
}());

黒い文字のテキストレイヤーを選んで実行すると、文字色が緑(RGB 0・255・0)に変わりました。

ヒストリーには「テキストレイヤーを編集」が1つ増えました。

Photoshopで「テスト見出し」の文字が緑になり、プロパティパネルのカラーも緑になった画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。テキストレイヤーの色を変える例を、黒い文字のテキストレイヤーを選んで実行した後の画面。

通常レイヤーを選んで実行すると、「テキストレイヤーを選択してください。」と表示され、文字色もヒストリーも変わりませんでした。

ファイルを選んで開く

開くファイルを利用者が選び、取消なら終了します。存在しても、形式・権限・破損等で開けない場合があります。エラー表示と実際に開いた文書を照合してください。

(function () {
    var file = File.openDialog("Photoshopで開く画像を選択してください");
    if (file === null) { return; }
    if (!file.exists) { alert("ファイルがありません。"); return; }
    try { app.open(file); } catch (error) { alert("開けません: " + error.message); }
}());

実行中のJSXのパスを読む

$.fileNameをFileへ渡し、OS形式のfsNameを読みます。URI表記とOSパスを混ぜたり、すでに復号済みの文字列へdecodeURIを重ねたりしません。コンソール表示とPhotoshopのアラートは異なります。

var scriptFile = new File($.fileName);
$.writeln(scriptFile.fsName);

[参照]から実行すると、Photoshopの画面には何も表示されませんでした。

$.writeln() の出力はPhotoshopの窓には出ないため、画面で確かめたいときは2行目を alert() に変えます。

var scriptFile = new File($.fileName);
alert(scriptFile.fsName);

この形で実行すると、「スクリプト警告」の窓に、実行したファイルのフルパスがWindowsの形式で表示されました。

Photoshopの「スクリプト警告」の窓に、実行したファイルのパスが表示された画面
2026-10-17撮影。Adobe Photoshop 2026 (27.11.0)、Windows 11 Pro (10.0.26200)。パスを読む例の2行目を alert() に変えて実行したときの窓。R: は確認用に割り当てた一時ドライブです(窓の部分だけ切り出し)。

文字列lengthが数える単位

lengthはUTF-16コード単位です。絵文字等の見た目1文字と一致するとは限りません。旧例はテキストレイヤーから取得せず固定文字列を処理していたため、レイヤーの文字数を自動取得する説明とは区別します。

var words = "あいうえお";
alert("UTF-16コード単位: " + words.length);

旧例の前面・マスク・削除・GIF・進捗を扱う場合

旧処理確認・改善が必要な点
bringToFront / 最前面・上下選択アプリ前面とレイヤー選択は別。Action Managerの指定は現在の選択・最上/下端・グループ条件で実機比較する。
hasLayerMaskUsrMによるユーザーマスクの検出はベクトルマスク等と区別。catchでfalseを返す旧例は、対象なしと読取エラーを区別できない。
artLayersの最背面削除layers全体の最背面やLayerSetと同じではない。削除対象を明示し、原本で実行しない。
rasterizeAllLayers / blendMode / opacityテキストやスマートオブジェクト等の編集情報を変える操作。対象型・ロック・文書モードを確認する。
GIF保存旧exportPngという関数名でもformatはGIF。PNG処理と誤認しない。保存先、既存出力、色数/透明/画質を別に確認する。
suspendHistory / progressbarヒストリーをまとめても失敗時の自動復元にはならない。進捗は処理済み件数で更新し、例外・取消でもUIを閉じる構成が必要。旧0開始では最後がmaxに届かない。

これらの旧コードはそのままの完成例としては扱いません。複製して別名PSD保存やScriptUIの入力・進捗・取消など、対象と失敗後の状態を定めた記事を使ってください。レイヤー削除や書き出しの成功は新例でも実機確認が必要です。

実行入口と旧ドラッグ画面

最初はファイル→スクリプト→参照で実行し、慣れたコードだけメニューへ登録します。下の旧ドラッグ画面は過去の記録で、今回の版でのドラッグ受付や成功を確認したものではありません。

旧記事のJSXドラッグ画面。「コピー」の表示とタブ周辺が写っています。実行成功を示すダイアログではありません。
旧記事のJSXドラッグ画面。「コピー」の表示とタブ周辺が写っています。実行成功を示すダイアログではありません。 過去の掲載画像で、撮影日・詳細版は未確認です。

旧コード・配布元・関連操作

旧コードの参照資料(実行しない)

旧25コードを原文で保持しています。末尾re、読取の前の背景解除、固定名/保存先、型確認のないtextItem、エラーをfalseに隠すマスク判定などを含みます。新例へ混ぜて実行しないでください。

旧コード 1

//--------------------------------------------------
// 関数
//--------------------------------------------------

旧コード 2

#target photoshop

function test(){
    try {
        //作成したスクリプト
    } catch (e){
        alert("エラー発生");
    }
}
test();

旧コード 3

(function(){
alert("テストだよ!");
})() ;

旧コード 4

(function(){
alert("テストだよ!");
}()) ;

旧コード 5

app.bringToFront();

旧コード 6

var doc= activeDocument;
var bg = doc.layers.length;
doc.layers[bg-1].isBackgroundLayer = false;

旧コード 7

function selectFront() {
    var idslct = charIDToTypeID( "slct" );
    var desc250 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
    var ref207 = new ActionReference();
    var idLyr = charIDToTypeID( "Lyr " );
    var idOrdn = charIDToTypeID( "Ordn" );
    var idFrnt = charIDToTypeID( "Frnt" );
    ref207.putEnumerated( idLyr, idOrdn, idFrnt );
    desc250.putReference( idnull, ref207 );
    var idMkVs = charIDToTypeID( "MkVs" );
    desc250.putBoolean( idMkVs, false );
    executeAction( idslct, desc250, DialogModes.NO );
}
selectFront();

旧コード 8

// 一つ上のレイヤーに移動
function selectLayerForward() {
  var desc = new ActionDescriptor();
  var ref = new ActionReference();
  ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Frwr" ) );
  desc.putReference( charIDToTypeID( "null" ), ref );
  desc.putBoolean( charIDToTypeID( "MkVs" ), false );
  executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}
selectLayerForward();

旧コード 9

// 一つ下のレイヤーに移動
function selectLayerBelow() {
  var desc = new ActionDescriptor();
  var ref = new ActionReference();
  ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Bckw" ) );
  desc.putReference( charIDToTypeID( "null" ), ref );
  desc.putBoolean( charIDToTypeID( "MkVs" ), false );
  executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}
selectLayerBelow();

旧コード 10

var doc=app.activeDocument;
doc.activeLayer=doc.layers.getByName("背景");  

旧コード 11

var doc = activeDocument;
var lay = doc.layers;
doc.activeLayer = lay[lay.length - 1]

旧コード 12

if(activeDocument.activeLayer.typename == "ArtLayer" && hasLayerMask() == true){
      alert("マスク有り");
        }

    else{
      alert("マスク無し");
}

// レイヤーマスクがあるかどうかの判定
function hasLayerMask() {
    var hasLayerMask = false;
    try {
        var ref = new ActionReference();
        var keyUserMaskEnabled = app.charIDToTypeID( 'UsrM' );
        ref.putProperty( app.charIDToTypeID( 'Prpr' ), keyUserMaskEnabled );
        ref.putEnumerated( app.charIDToTypeID( 'Lyr ' ), app.charIDToTypeID( 'Ordn' ), app.charIDToTypeID( 'Trgt' ) );
        var desc = executeActionGet( ref );
        if ( desc.hasKey( keyUserMaskEnabled ) ) {
            hasLayerMask = true;
            }
        }catch(e) {
            hasLayerMask = false;
            }
        return hasLayerMask;
}

旧コード 13

var doc=app.activeDocument;
var lay=doc.artLayers.getByName("背景");
lay.visible = false; 

旧コード 14

//一番下のレイヤーの削除
var layObj = activeDocument.artLayers;
var bgLayer = layObj[layObj.length-1];
bgLayer.remove();

旧コード 15

activeDocument.rasterizeAllLayers();

旧コード 16

doc = activeDocument; 
doc.activeLayer.blendMode  = BlendMode.MULTIPLY;
doc.activeLayer.opacity = 10;

旧コード 17

var doc = app.activeDocument;
var docName = doc.name;
var docPath = "~/Desktop";//PSDと同じ階層下に書き出したい時はvar docPath = doc.pathにする
var folder  = new Folder(docPath);
if (docName.indexOf(".") != -1) {
    var basename = docName.match(/(.*)\.[^\.]+$/)[1];
}
else {
    var basename = docName;
}
exportPng(doc, folder, basename+ '.gif');

function exportPng(doc, folder, name) {
    var file = new File(folder.fsName + "/" + name);
    var options = new ExportOptionsSaveForWeb(); 
    options.format = SaveDocumentType.COMPUSERVEGIF;
    options.quality = 0;
    doc.exportDocument(file, ExportType.SAVEFORWEB, options);
}

旧コード 18

openSpecificFile("~/Desktop/sample.psd");

function openSpecificFile(path){
    var filename = new File(path);
     open(filename);
}

旧コード 19

var filePath = decodeURI(File($.fileName));
$.writeln(filePath);

旧コード 20

var str ="あいうえお.jsx"
$.writeln(baseName(str));

function baseName(str) {
    var base = new String(str).substring(str.lastIndexOf('/') + 1);
    if (base.lastIndexOf(".") != -1)
        base = base.substring(0, base.lastIndexOf("."));
    return base;
}

旧コード 21

var doc = activeDocument;
var layers = doc.layers;
var arr = [];
layers[layers.length - 1].isBackgroundLayer = false;//背景レイヤーの解除

doc.suspendHistory("ヒストリー名", "main()");

function main() {
    getLayerName();
    var list = arr.join("\n");
    alert(list);
}

function getLayerName() {
    for (var i = 0; i < layers.length; i++) {
        var item = layers[i];
        var name = item.name;
        arr.push(name);
    }
    re

旧コード 22

var doc = activeDocument;
var layers = doc.layers;
var arr = [];
layers[layers.length - 1].isBackgroundLayer = false; //背景レイヤーの解除

doc.suspendHistory("ヒストリー名", "main()");

function main() {
    getLayerName(activeDocument);
    var list = arr.join("\n");
    alert(list);
}

function getLayerName(parent) {
    var childLayers = parent.layers;
    for (var i = 0; i < childLayers.length; i++) {
        if (childLayers[i].typename == "LayerSet") {
            getLayerName(childLayers[i]);
        }
        arr.push(childLayers[i].name);
    }
}

旧コード 23

var doc = activeDocument;   
var lay = doc.layers;
var arr = [];
doc.suspendHistory("ヒストリー名", "main()");

function main() {
    var win = new Window("palette", "loading…");
    var max = lay.length;
    win.progressbar = win.add("Progressbar", [10, 10, 300, 20], 0, max);
    win.center();
    win.show();

    for (var i = 0; i < max; i++) {
        arr.push(lay[i].name);
        win.progressbar.value = i;
        $.sleep(10);//インクリメントする事に処理を少しだけ止める  
        win.update();//ダイアログの状況を更新
    }
    win.close();
    var list = arr.join("\n");
    alert(list);    
}

旧コード 24

layer = app.activeDocument.activeLayer;

layer.textItem.color.rgb.red = 0;
layer.textItem.color.rgb.green = 255;
layer.textItem.color.rgb.blue = 0;

旧コード 25

var words = "あいうえお";
words = words.replace(/(\r\n|\n|\r)/gm," ");
while (words.indexOf("  ") != -1) {words = words.replace("  ", " ")};
var endSpace = /\s$/;
words = words.replace(endSpace, "");
var charCount = words.split(" ").join(" ").length;
alert ("\n "+ charCount + " Characters");

旧GitHubコード集は更新していません。以下は個別の完成例・操作目的へ進む導線です。

よくある質問:PhotoshopのJSXの書き方とコード例

この記事のコードは、何のためのものですか?

PhotoshopのExtendScript(.jsx)で、文書の有無、レイヤーの階層、名前の一致、テキスト型、ファイルの取消を確認する、短いコード例です。コピーして全部を連結するコード集ではありません。各例を別ファイルへ保存し、変更する例は自作文書のコピーで確認します。UXPの.psjsとはAPIが異なるため、JSXとPSJSの違いも確認してください。

コードを使う前に、何を確認しますか?

操作ごとに、文書への変更の有無が違います。文書名・レイヤー一覧の読み取りだけなら、背景解除・ラスタライズ・保存は不要です。レイヤー選択は、同じ名前が複数ある場合は停止し、選択状態は変わりますが保存はしません。背景解除・文字色は、レイヤー情報を変更するため、コピーで試し、確認後は元に戻すか、保存せずに閉じます。ファイルを開く場合は、取消・存在・読込失敗を区別し、文書が増えるため対象を再確認します。削除・統合・書き出しは、原本で実行しないでください。

try/catchは、編集を取り消してくれますか?

いいえ。try/catchは失敗を通知する仕組みで、途中の編集を取り消す機能ではありません。即時関数は、変数を関数内にまとめる書き方で、ドラッグ実行を有効にする必須の条件ではありません。

レイヤー名は、どう読みますか?

doc.layersは、最上位のArtLayerとLayerSetを含みます。グループ内を読む場合は、グループ名も先に記録して、子レイヤーへ進む再帰で読みます。出力順はこの走査順です。階層パスに同名があると同じ文字列になるため、固有IDや選択順を表す値には使いません。名前を読むための背景解除は不要です。旧例には、末尾のreと閉じ括弧の不足があり、構文・実行エラーにつながるため、新例には含めていません。

名前でレイヤーを選ぶときの注意点は?

記事の例では、CGM_targetを探す名前に変更し、0件または2件以上なら選択しません。layers.getByNameだけで、同名やグループ内の対象を一律に選べるとは扱わず、範囲と一致件数を明示します。

背景レイヤーや、テキストレイヤーの色を変えるときは?

背景レイヤーを通常レイヤーに変える例は編集操作で、最背面のレイヤーを背景と推定せず、isBackgroundLayerがtrueのArtLayerだけを変更します。背景がない場合は、任意の最背面レイヤーを変更しません。テキストの色を変える例は、ArtLayerかつLayerKind.TEXTを確認してから、文字色を設定します。通常レイヤーやグループには、textItemを読ませません。複数の文字色を持つテキストの保持は、この例の目的に含めず、全体の色を変える操作としてコピーで確認します。

ファイルを開く、実行中のJSXのパスを読む、文字数を数える例の注意点は?

ファイルを選んで開く例は、利用者がファイルを選び、取消なら終了します。存在しても、形式・権限・破損等で開けない場合があるため、エラー表示と実際に開いた文書を照合してください。実行中のJSXのパスは、$.fileNameをFileへ渡し、OS形式のfsNameを読みます。URI表記とOSパスを混ぜたり、すでに復号済みの文字列へdecodeURIを重ねたりしません。文字数を数えるlengthは、UTF-16コード単位で、絵文字等の見た目1文字と一致するとは限りません。旧例はテキストレイヤーから取得せず、固定文字列を処理していたため、レイヤーの文字数を自動取得する説明とは区別します。

[参照]から実行した場合、$.writeln() の出力はPhotoshopの画面に出ないため、パスを見るには alert() を使います(2026年10月17日に確認)。

旧記事の25コードは、どうなりましたか? 実機で確認されていますか?

旧25コードは、後半の参照資料に原文で保持されています。

末尾のre、読取の前の背景解除、固定名/保存先、型確認のないtextItem、エラーをfalseに隠すマスク判定などを含み、新例へ混ぜて実行しないでください。

旧GitHubコード集は更新していません。

新例のうち5本は、2026年10月17日にPhotoshop 2026(27.11.0)とWindows 11 Pro(10.0.26200)で[参照]から実行し、記事の説明どおりに動くことを確かめました。

最上位の名前、背景の解除、ファイルを選んで開く、文字列の長さの4本と、旧25コードは実行していません。

最新はAdobe公式のScripting Guideなどの資料で確認してください。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

Photoshopのおすすめ書籍

動作要件とPCの確認項目

周辺機器の優先度

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次