5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Photoshopで疑似網点生成するjsx

Last updated at Posted at 2025-06-16

Photoshopに疑似AM網点を生成させます。
アクションでできるのですが、網角と線数を都度設定したくて。

SS_Adobe Photoshop 2025_20250616-151130.png

90%GPTコードです。
https://d.pr/f/wBD4ex

使い方

何でも良いんですが、
Illustratorデータを網点化してみましょう。

PhotoshopはIllustratorPDFの完璧なラスタライズはできません。Finder(QuickLook)やPreview.appと同程度の解釈しかできず、Acrobat(=印刷)と同じにはならないこともあります。

▼Photoshopで読み込むのはPDF部分なので、PDF互換ファイルを付けてください
SS_Finder_20250616-150028.png

aiファイルをPhotoshopに読ませると、ラスタライズ設定が出ます。
▼アンチエイリアスオフ、2,400ppiのCMYKでラスタライズさせてください。
SS_Finder_20250616-150055.png

▼開いたら、スクリプトを実行。プリセットにK45とM45、7度振りがあります。
SS_Finder_20250616-150122.png

網点化されます。
Photoshopの2階調ハーフトーンスクリーンはあくまでもPhotoshopの網点ですので、商業印刷で同じ形状にはなりませんし、モアレの確認などもってのほかですが、学習用としては使えます。

▼画像統合の上、チャンネル選択して全チャンネルの目玉を表示状態にしてから……
SS_Finder_20250616-150805.png

▼移動ツールでチャンネルごとにずらせば、版ズレのシミュレーションもできます。
名称未設定-1.png

以下コード

/*
<javascriptresource>
<name>疑似網点生成CMYK</name>
<category>YPresets</category>
</javascriptresource>
*/

(function () {

var isGray = app.activeDocument.mode === DocumentMode.GRAYSCALE;
var presetTable = [
  ["CMYK", "M45_175線", 15, 45, 0, 75, 175, 175, 175, 175],
  ["CMYK", "K45_300線", 15, 75, 0, 45, 175, 175, 175, 175],
  ["CMYK", "7度_175(Y190)線", 22, 52, 7, 82, 175, 175, 190, 175],
  ["GRAY", "45度_175線", 45, 175],
  ["GRAY", "45度_80線", 45, 80],
  ["GRAY", "45度_300線", 45, 300]
];
var keys = isGray ? ["Gray"] : ["C", "M", "Y", "K"];

function buildDialog() {
  var dlg = new Window("dialog", "線数と角度の設定");
  dlg.orientation = "column";
  dlg.alignChildren = "left";

  var mode = isGray ? "GRAY" : "CMYK";
  var filtered = [];
  for (var i = 0; i < presetTable.length; i++) {
    if (presetTable[i][0] === mode) {
      filtered.push(presetTable[i]);
    }
  }
  var presetNames = [];
  for (var i = 0; i < filtered.length; i++) {
    presetNames.push(filtered[i][1]);
  }

  var presetList = dlg.add("dropdownlist", undefined, presetNames);
  presetList.selection = 0;

  var inputGroup = dlg.add("group");
  inputGroup.orientation = "column";
  var inputFields = {};

  for (var i = 0; i < keys.length; i++) {
    var row = inputGroup.add("group");
    row.add("statictext", undefined, keys[i] + ": 角度");
    inputFields[keys[i]] = {};
    inputFields[keys[i]].angle = row.add("edittext", undefined, "0");
    inputFields[keys[i]].angle.characters = 5;
    row.add("statictext", undefined, "線数");
    inputFields[keys[i]].lpi = row.add("edittext", undefined, "0");
    inputFields[keys[i]].lpi.characters = 5;
  }

  var resGroup = dlg.add("group");
  resGroup.add("statictext", undefined, "出力解像度:");
  var resDropdown = resGroup.add("dropdownlist", undefined, ["4800", "2400", "1200", "600"]);
  resDropdown.selection = 1;
  inputFields.resolution = resDropdown;

  presetList.onChange = function () {
    var sel = filtered[presetList.selection.index];
    if (mode === "GRAY") {
      inputFields["Gray"].angle.text = sel[2];
      inputFields["Gray"].lpi.text = sel[3];
    } else {
      var angles = sel.slice(2, 6);
      var lpis = sel.slice(6);
      var ch = ["C", "M", "Y", "K"];
      for (var i = 0; i < ch.length; i++) {
        inputFields[ch[i]].angle.text = angles[i];
        inputFields[ch[i]].lpi.text = lpis[i];
      }
    }
  };
  presetList.notify();
  // 注意文をパネルで追加
  var notePanel = dlg.add("panel", undefined, "注意");
  notePanel.orientation = "column";
  notePanel.alignChildren = "left";
  notePanel.margins = [10, 15, 10, 10];

  var note = notePanel.add("statictext", undefined,
    "元画像を複製して処理します。\n※先に画像解像度で、使用サイズ&解像度にリサイズし、統合してから実行してください。\nESCでキャンセル",
    { multiline: true }
  );
  note.maximumSize.width = 380;
  dlg.add("group").add("button", undefined, "OK");

  return dlg.show() == 1 ? inputFields : null;
}

function getScreenSettings(fields) {
  var s = {};
  for (var i = 0; i < keys.length; i++) {
    s[keys[i]] = {
      angle: parseFloat(fields[keys[i]].angle.text),
      lpi: parseFloat(fields[keys[i]].lpi.text)
    };
  }
  s.resolution = parseInt(fields.resolution.selection.text, 10);
  return s;
}

function binarizeChannel(doc, setting, resolution) {
  app.activeDocument = doc;
  // doc.resizeImage(undefined, undefined, resolution, ResampleMethod.NONE); // 解像度変更を無効化
  var bmo = new BitmapConversionOptions();
  bmo.resolution = resolution;
  bmo.method = BitmapConversionType.HALFTONESCREEN;
  bmo.frequency = setting.lpi;
  bmo.angle = setting.angle;
  bmo.shape = BitmapHalfToneType.ROUND;
  doc.changeMode(ChangeMode.BITMAP, bmo);
  doc.changeMode(ChangeMode.GRAYSCALE);
}

function mergeCMYKChannels(docNames) {
  var desc = new ActionDescriptor();
  var list = new ActionList();
  for (var i = 0; i < 4; i++) {
    var ref = new ActionReference();
    ref.putName(stringIDToTypeID("document"), docNames[i]);
    list.putReference(ref);
  }
  desc.putList(stringIDToTypeID("null"), list);
  desc.putEnumerated(stringIDToTypeID("mode"), stringIDToTypeID("colorSpace"), stringIDToTypeID("CMYKColorEnum"));
  try {
    executeAction(stringIDToTypeID("mergeChannels"), desc, DialogModes.NO);
  } catch (e) {
    alert("mergeChannels に失敗しました\n" + e);
  }
}

if (app.documents.length === 0 ||
    !(app.activeDocument.mode === DocumentMode.CMYK || app.activeDocument.mode === DocumentMode.GRAYSCALE)) {
  alert("CMYKまたはグレースケールモードの画像を開いてから実行してください。");
  return;
}

var inputFields = buildDialog();
if (!inputFields) return;

var screenSettings = getScreenSettings(inputFields);
var resolution = screenSettings.resolution;
var doc = app.activeDocument;
var dup = doc.duplicate(doc.name.replace(/\.[^\.]+$/, "") + "_複製", true);
try {
  dup.flatten();
} catch (e) {
  // 統合済みで flatten が不要な場合はスキップ
}
app.activeDocument = dup;
var splitDocs;
if (isGray) {
  splitDocs = [dup];
} else {
  splitDocs = dup.splitChannels();
}

var binarizedDocs = [];
for (var i = 0; i < keys.length; i++) {
  binarizeChannel(splitDocs[i], screenSettings[keys[i]], resolution);
  binarizedDocs.push(splitDocs[i]);
}

if (!isGray) {
  var docNames = [];
  for (var i = 0; i < binarizedDocs.length; i++) {
    docNames.push(binarizedDocs[i].name);
  }
  mergeCMYKChannels(docNames);
}

})();

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?