m1b
Community Expert
m1b
Community Expert
Activity
Apr 01, 2025
You're welcome!
Yes ChatGPT can be a great help but you need to understand what you're getting. It is very common for ChatGPT to make up (confabulate) API features that don't actually exist, for example.
- Mark
... View more
Apr 01, 2025
1 Upvote
@Robert at ID-Tasker
> Are you fully aware of the drawback - that you'll lose threading between TextFrames located on different pages?
I believe I fixed that issue.
@Peter Spier haha no problem! I love that the OPs problem is TOO MANY scripts! I actually learned quite a lot from this exercise, even though I doubt that I'd ever need this exact script myself. 🙂
@aniri5j9ox8tw2ln I've put a UI now so that will make things easier.
... View more
Apr 01, 2025
03:27 AM
@aniri5j9ox8tw2ln I mean my script does that exactly, so feel free to try it.
You just need to set pageCount to
pageCount: 50,
and you can also adjust this line:
fileNameTemplate: "Output/{docName}_pages {pageStart}-{pageEnd}.indd",
This is how the output folder and file name is derived.
- Mark
... View more
Apr 01, 2025
02:43 AM
Robert, I noticed that duplicating a range of Pages keeps threads intact, and that look promising, but then I realised that a spread cannot have more than 10 pages so I could only duplicate maximum of 9 pages, which is a dealbreaker here. Then I realised that the best way was just to delete the pages we didn't want. Much easier. I did have to write functions to handle the text thread cutting, but they seem to work in most normal cases.
- Mark
... View more
Mar 31, 2025
04:11 PM
@Robert at ID-Tasker Yes I was disappointed that it didn't preserve the threaded frames across spreads. It does across duplicated *pages* though. Maybe I should duplicate pages and then re-organise into spreads. Hmm.
... View more
Mar 31, 2025
10:11 AM
1 Upvote
Hi @aniri5j9ox8tw2ln and others, I'm not sure if the script Peter posted might do the trick, but I've written my own version for fun. Maybe it will be useful, too. I don't duplicate to new documents, because then you lose lots of document settings. It's a quick script so will definitely have bugs in some cases. I'm tempted to add I added a UI.
- Mark
/**
* @file Divide Document.js
*
* Outputs new Indesign documents comprising
* sequences of pages of the active document.
*
* Makes attempt to cleanly cut text threads but
* some complex cases may not work properly.
*
* @author m1b
* @version 2025-04-02
* @discussion https://community.adobe.com/t5/indesign-discussions/split-id-document-can-anybody-change-this-script/m-p/15241392#M618671
*/
function main() {
var settings = {
/** number of pages in each created document */
pageCount: 50,
/** path inside the parent folder and file name with template tokens */
fileNameTemplate: "Output/{docName}_pages {pageStart}-{pageEnd}.indd",
/** whether to keep the divided documents section numbering start */
keepPageNumbering: true,
/** whether to reveal the folder in the OS afterwards */
revealFolder: true,
/** whether to show the UI */
showUI: true,
};
if (0 === app.documents.length)
return alert("Please open a document and try again.");
var doc = settings.doc = app.activeDocument;
if (!doc.saved)
return alert("Please save the document first.");
if (settings.showUI) {
var result = ui(settings);
if (2 === result)
// user cancelled
return;
}
doc.documentPreferences.properties = {
allowPageShuffle: false,
preserveLayoutWhenShuffling: true,
};
var docName = doc.name.replace(/\.[^\.]+$/, '');
var filePath = doc.filePath,
f;
var totalPages = doc.pages.length;
var len = Math.ceil(totalPages / settings.pageCount);
for (var i = 0; i < len; i++) {
var start = i * settings.pageCount,
end = Math.min(start + settings.pageCount - 1, totalPages - 1);
// open a copy of the document
var newDoc = app.open(doc.fullName, true, OpenOptions.OPEN_COPY);
// the pages we want
var targetPages = newDoc.pages.itemByRange(end, start).getElements();
var firstPage = targetPages[0],
lastPage = targetPages[targetPages.length - 1];
var firstPageOffset = firstPage.documentOffset;
// cut threads to these pages
cutTextThreads(firstPage, lastPage);
// remove the unwanted pages
deleteAllPagesExceptRange(newDoc, firstPage, lastPage);
if (settings.keepPageNumbering)
newDoc.pages[0].appliedSection.properties = {
continueNumbering: false,
pageNumberStart: firstPageOffset + 1,
};
// populate the file name using the template
var fileName = settings.fileNameTemplate
.replace(/^\/?/, "/") // add leading slash
.replace(/\{docName\}/g, docName)
.replace(/\{pageStart\}/g, doc.pages[start].name) /* || newDoc.pages[start].pages[0].name)*/
.replace(/\{pageEnd\}/g, doc.pages[end].name); /* || newDoc.pages[end].pages[-1].name);*/
// the file to save
f = new File(filePath + fileName);
if (!f.parent.exists)
f.parent.create();
newDoc.save(f);
newDoc.close(SaveOptions.NO);
}
if (settings.revealFolder)
// reveal output folder
f.parent.execute();
};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Divide Document');
/**
* Cuts text frame threading.
* - provide `startPage` to cut text threads before.
* - provide `endPage` to cut text threads after.
* @author m1b
* @version 2025-04-01
* @param {Page} [startPage] - the start page where the threads should be cut.
* @param {Page} [endPage] - the end page where the threads should be cut.
*/
function cutTextThreads(startPage, endPage) {
if (startPage) {
// cut text before this page
for (var i = 0; i < startPage.textFrames.length; i++)
cutTextFrame(startPage.textFrames[i], false);
}
if (endPage) {
// cut text after this page
for (var i = 0; i < endPage.textFrames.length; i++)
if (endPage.textFrames[i].nextTextFrame)
cutTextFrame(endPage.textFrames[i].nextTextFrame, false);
}
};
/**
* Cuts the text frame's story thread, so that
* the story starts in this text frame.
* @author m1b
* @version 2025-04-01
* @param {TextFrame} tf - the textframe to cut.
* @param {Boolean} [cutThreadOnSamePage] - whether to cut the thread even if the previous text frame is on the same page (default: false).
*/
function cutTextFrame(tf, cutThreadOnSamePage) {
var previous = tf.previousTextFrame;
if (!previous)
return;
if (
!cutThreadOnSamePage
&& previous.parentPage === tf.parentPage
)
return;
var story = tf.parentStory,
index = tf.characters[0].index;
tf.previousTextFrame = null;
story.characters.itemByRange(index, story.length - 1).move(LocationOptions.AT_BEGINNING, tf);
};
/**
* Deletes all pages of `doc` before `firstPage` and after `lastPage`.
* @author m1b
* @version 2025-04-01
* @param {Document} doc - an Indesign document.
* @param {Page} firstPage - the first page to keep.
* @param {Page} lastPage - the last page to keep.
*/
function deleteAllPagesExceptRange(doc, firstPage, lastPage) {
var minPageOffset = doc.pages.firstItem().documentOffset,
maxPageOffset = doc.pages.lastItem().documentOffset;
// the pages we don't want
var deleteBeforeA = minPageOffset,
deleteBeforeB = Math.max(minPageOffset, firstPage.documentOffset - 1),
deleteAfterA = Math.min(maxPageOffset, lastPage.documentOffset + 1),
deleteAfterB = maxPageOffset;
if (deleteAfterB - deleteAfterA > 0)
// remove pages after
doc.pages.itemByRange(deleteAfterA, deleteAfterB).remove();
if (deleteBeforeB - deleteBeforeA > 0)
// remove pages before
doc.pages.itemByRange(deleteBeforeA, deleteBeforeB).remove();
};
/**
* Shows UI for Divide Document Script
* @param {Object} settings - the settings to adjust via UI.
* @returns {1|2} - result code
*/
function ui(settings) {
loadSettings();
// make the dialog
var w = new Window("dialog", 'Divide Document', undefined),
group0 = w.add("group {orientation:'row', alignment:['fill','top'], alignChildren:['left','top'], margins:[10,10,10,10] }"),
group1 = group0.add("group {orientation:'column', alignment:['fill','top'], alignChildren:['left','top'], margins:[10,10,10,10] }"),
group2 = group0.add("group {orientation:'column', alignment:['fill','top'], alignChildren:['left','top'], margins:[10,10,10,10] }"),
label1 = group1.add('statictext {preferredSize: [160,-1], text:"Pages Per Division:", justify: "left"}'),
group2a = group1.add("group {orientation:'row' }"),
pageCountField = group2a.add('edittext {preferredSize: [60,-1], text:""}'),
multiplierLabel = group2a.add('statictext {preferredSize: [100,20], text:"", justify: "left"}'),
keepPageNumberingCheckBox = group1.add("CheckBox { text: 'Keep Numbering', alignment:['left','top'] }"),
label2 = group2.add('statictext {text:"Filename Template:", justify: "left"}'),
fileNameTemplateField = group2.add('edittext {preferredSize: [450,-1], text:""}'),
infoText = group2.add('statictext {text:"", preferredSize:[350,-1], alignment:["fill","bottom"], justify: "left"}'),
bottom = w.add("group {orientation:'row', alignment:['fill','bottom'], alignChildren:['fill','bottom'] }"),
infoGroup = bottom.add("group {orientation:'row', alignment:['fill','bottom'], margins:[0,0,0,6] }"),
buttons = bottom.add("Group { orientation: 'row', alignment: ['right','bottom'], margins:[0,0,0,6] }"),
hints = infoGroup.add('statictext {text:"", justify: "left"}'),
cancelButton = buttons.add("Button { text:'Cancel', properties:{name:'cancel'} }"),
divideButton = buttons.add("Button { text:'Divide', enabled: true, name: 'ok' }");
// populate UI
keepPageNumberingCheckBox.value = (true === settings.keepPageNumbering);
pageCountField.text = settings.pageCount;
fileNameTemplateField.text = settings.fileNameTemplate;
hints.text = 'Placeholders: {docName} {pageStart} {pageEnd} {part}';
updateUI();
// event handlers
pageCountField.onChanging = updateUI;
fileNameTemplateField.onChanging = updateUI;
divideButton.onClick = done;
w.center();
return w.show();
function getPartCount() {
var partCount = Math.ceil(settings.doc.pages.length / Number(pageCountField.text));
if (
!pageCountField.text
|| isNaN(partCount)
)
return;
return partCount;
};
function updateUI() {
var partCount = getPartCount();
divideButton.enabled = undefined != partCount;
if (!partCount)
return;
multiplierLabel.text = '\u00D7 ' + partCount + ' documents';
// show mock filename
infoText.text = 'Example: ' + fileNameTemplateField.text
.replace(/^\/?/, "/") // add leading slash
.replace(/\{docName\}/g, settings.doc.name.replace(/\.[^\.]+$/, ''))
.replace(/\{pageStart\}/g, 1)
.replace(/\{pageEnd\}/g, pageCountField.text)
.replace(/\{part\}/g, partCount);
};
function done() {
// update settings
settings.fileNameTemplate = fileNameTemplateField.text;
settings.keepPageNumbering = keepPageNumberingCheckBox.value;
settings.pageCount = Number(pageCountField.text);
saveSettings();
// close window with success code
w.close(1);
};
function loadSettings() {
// load last-used settings from document
settings.pageCount = Number(settings.doc.extractLabel('pageCount') || settings.pageCount);
settings.fileNameTemplate = settings.doc.extractLabel('fileNameTemplate') || settings.fileNameTemplate;
var keepPageNumbering = settings.doc.extractLabel('keepPageNumbering');
settings.keepPageNumbering = '' == keepPageNumbering
? settings.keepPageNumbering
: 'FALSE' === keepPageNumbering;
};
function saveSettings() {
// store last-used languages in document
settings.doc.insertLabel('fileNameTemplate', settings.fileNameTemplate);
settings.doc.insertLabel('keepPageNumbering', (settings.keepPageNumbering ? "TRUE" : "FALSE"));
settings.doc.insertLabel('pageCount', String(settings.pageCount));
};
};
Edit 2025-04-01: improved script—now will keep text threads intact in most cases, and handle arbitrary spread sizes.
Edit 2025-04-02: added a UI.
... View more
Mar 29, 2025
03:44 PM
Not that I know of. Sadly.
- Mark
... View more
Mar 29, 2025
02:12 PM
Hi @Oscar5C13 this seems to be a problem introduced by the latest Photoshop Beta. Uninstalling it should fix. If not, search this forum for similar posts.
- Mark
... View more
Mar 29, 2025
08:06 AM
You're welcome. It might need some changes to work with Arabic or other RTL text though.
... View more
Mar 28, 2025
09:43 AM
@Bedazzled532 I notice in your example screenshot you have justified text. Just for fun I've updated the script above to handle left-justified text so that the frame can be expanded without interfering with the spacing.
- Mark
... View more
Mar 28, 2025
07:32 AM
Ha, no problem! You are learning English very well and much better than I can speak other languages. You never give up!
... View more
Mar 28, 2025
04:49 AM
Is it a Guide?
app.activeDocument.layoutWindows[0].activeSpread.guides.add(layer, {
orientation: HorizontalOrVertical.VERTICAL,
location: x1 + mouthWidth,
});
or a GraphicLine? If so then use the drawGraphicLine function. I wrote documentation for it.
- Mark
... View more
Mar 28, 2025
03:42 AM
I already drew it in my new code:
drawGraphicLine([x1 + mouthWidth, y1], [x1 + mouthWidth, y1 - cropMarkLength], group, props);
drawGraphicLine([x1 + mouthWidth, y2], [x1 + mouthWidth, y2 + cropMarkLength], group, props);
This is easier to use: just provide two [x, y] points for the two points of the line.
Note that Indesign's geometric or visible bounds (or page bounds) are all [top, left, bottom, right] which can be confusing.
- Mark
... View more
Mar 28, 2025
02:37 AM
2 Upvotes
Hi @Bedazzled532, try this script. You need to set the name of the target paragraph style in the settings object. Let me know if it works for you.
- Mark
/**
* @file Force Line Breaks.js
*
* Adds a line break at the end of every line of text
* of selected items or, optionally, the whole document.
*
* Notes:
* - only processes text in the target paragraph style
* (edit the settings object below).
* - makes a valiant attempt at hardening justified text,
* but only handles left-justified text.
*
* @author m1b
* @version 2025-03-29
* @discussion https://community.adobe.com/t5/indesign-discussions/soft-return-at-end-of-line/m-p/15236469
*/
function main() {
var settings = {
/* only paragraphs in this style will be processed (set to `undefined` to disable filtering) */
paragraphStyleName: 'My Best Paragraph Style',
};
app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;
const EXPAND_JUSTIFIED_TEXT_FRAME = 3,
SQUASH_AMOUNT = -100;
var doc = app.activeDocument,
stories = getSelectedStories(doc.selection);
if (0 === stories.length) {
// check with user
if (!confirm('Do you want to apply to whole document?'))
return;
// no selected stories, so get every story from document
stories = doc.stories.everyItem().getElements();
}
var spaceCharacter = /\s/,
linefeeds = /[\n\r]/;
// we'll slightly expand the text frames later on
var framesToAdjust = {};
storyLoop:
for (var i = stories.length - 1; i >= 0; i--) {
var paragraphs = stories[i].paragraphs.everyItem().getElements();
paragraphsLoop:
for (var j = paragraphs.length - 1; j >= 0; j--) {
var paragraph = paragraphs[j];
if (
undefined != settings.paragraphStyleName
&& settings.paragraphStyleName !== paragraph.appliedParagraphStyle.name
)
continue paragraphsLoop;
var isJustified = (Justification.LEFT_JUSTIFIED === paragraph.justification);
var lines = paragraph.lines.everyItem().getElements(),
// store character positions
positions = [];
linesLoop:
for (var k = lines.length - 1; k >= 0; k--) {
var line = lines[k],
suffix;
if (0 === line.parentTextFrames.length)
continue linesLoop;
if (
linefeeds.test(line.characters[-1].contents)
|| SpecialCharacters.FORCED_LINE_BREAK === line.characters[-1].contents
|| !line.parentStory.characters[line.characters[-1].index + 1].isValid
)
// last line in paragraph or story
continue linesLoop;
suffix = !spaceCharacter.test(line.characters[-1].contents)
? suffix = '-\n' // hyphenated word
: suffix = '\n';
if (isJustified)
// store positions for later
positions.unshift(line.characters.everyItem().horizontalOffset);
// force line break
line.insertionPoints[-1].contents = suffix;
}
if (!isJustified)
continue paragraphsLoop;
// now we harden the justification, line by line
// start by aligning left (let me know if you need RTL)
paragraph.justification = Justification.LEFT_ALIGN;
// collect all the parent text frames
for (var f = 0; f < paragraph.parentTextFrames.length; f++) {
var tf = paragraph.parentTextFrames[f];
if (!framesToAdjust[tf.id])
framesToAdjust[tf.id] = tf;
}
// temporarily squash text up a bit to stop unwanted line breaking
squashLoop:
for (var k = paragraph.lines.length - 2; k >= 0; k--) {
if (
!paragraph.lines[k].isValid
|| 0 === paragraph.lines[k].parentTextFrames.length
)
continue squashLoop;
paragraph.lines[k].characters.itemByRange(
paragraph.lines[k].characters[0],
paragraph.lines[k].characters[-4]
).tracking = SQUASH_AMOUNT;
}
// refresh the lines reference
lines = paragraph.lines.everyItem().getElements();
linePositionsLoop:
for (var l = 0; l < lines.length; l++) {
var linePositions = positions[l];
if (!linePositions)
continue linePositionsLoop;
var len = Math.min(lines[l].characters.length, linePositions.length);
charactersLoop:
for (var c = 1; c < len; c++) {
var ch0 = paragraph.lines[l].characters[c - 1],
ch1 = paragraph.lines[l].characters[c],
pos = ch1.horizontalOffset,
target = linePositions[c];
if (undefined == target)
continue charactersLoop;
ch0.tracking += (target - pos) * (1000 / ch0.pointSize);
}
}
}
}
};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Force Line Breaks');
/**
* Returns the document's selected stories.
* @author m1b
* @version 2025-03-26
* @param {Array<PageItem>} items - the items from which to gather stories.
* @returns {Array<Story>}
*/
function getSelectedStories(items) {
var stories = [],
unique = {};
for (var i = 0; i < items.length; i++) {
if ('TextFrame' === items[i].constructor.name) {
if (unique[items[i].parentStory.id])
// already collected this story
continue;
unique[items[i].parentStory.id] = true;
items[i] = items[i].parentStory;
}
if ('function' === typeof items[i].changeGrep)
stories.push(items[i]);
}
return stories;
};
Edit 2025-03-29: added handling of left-justified text; it will "harden" the justification using custom tracking and the lines are fixed, even if you expand the text frame. Like this:
... View more
Mar 28, 2025
01:38 AM
Hey @dublove I find the functions not easy to use for me, so I've refactored the code—not as much as I want to, but at least to make it easier to work with (I hope!). In this version I removed all the "my" variables—unnecessary!—and cleaned up a few things here and there, but mostly I made better functions for creating the lines and registration target marks.
And I added in a couple of lines to draw the mouth lines. See what you think.
- Mark
/* CropMarks.jsx
Draws crop and/or registration marks around the selected object or objects.
For more on InDesign scripting, go to http://www.adobe.com/products/indesign/scripting.html
or visit the InDesign Scripting User to User forum at http://www.adobeforums.com
Based on CropMarks.jsx
Modified by dublove
Modified 2025-03-28 by m1b
*/
function main() {
app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;
var mm = 2.83465;
if (app.documents.length === 0)
return alert("Ple请打开一个文档,选择一个物体再试,呵呵");
if (app.selection.length == 0)
return alert("请选择一个物体再试,呵呵.");
if (!app.selection[0].geometricBounds)
return alert("选择一个页面消息再试.");
var doc = app.activeDocument;
// create dialog
var dialog = app.dialogs.add({ name: "DrawCropMarks" });
with (dialog) {
with (dialogColumns.add()) {
var cropMarksGroup = enablingGroups.add({ staticLabel: "CropMarks", checkedState: true });
with (cropMarksGroup) {
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Option:" });
with (dialogColumns.add()) {
staticTexts.add({ staticLabel: "lengths:" });
staticTexts.add({ staticLabel: "offset:" });
staticTexts.add({ staticLabel: "Thickness:" });
staticTexts.add({ staticLabel: "Spine:" });
staticTexts.add({ staticLabel: "Mouth:" });
}
with (dialogColumns.add()) {
//看到的界面单位是毫米,运算前的值为点,所以要奖毫米折算为点(即,毫米值乘于2.8345)进行
var cropMarkLengthField = measurementEditboxes.add({ editValue: (3 * mm), editUnits: MeasurementUnits.millimeters });
var cropMarkOffsetField = measurementEditboxes.add({ editValue: (3 * mm), editUnits: MeasurementUnits.millimeters });
var cropMarkWidthField = measurementEditboxes.add({ editValue: (0.1 * mm), editUnits: MeasurementUnits.millimeters });
//新增 书脊 勒口
var spineWidthField = measurementEditboxes.add({ editValue: (20 * mm), editUnits: MeasurementUnits.millimeters });
var mouthWidthField = measurementEditboxes.add({ editValue: (83 * mm), editUnits: MeasurementUnits.millimeters });
}
}
}
var regMarksGroup = enablingGroups.add({ staticLabel: "alignment mark", checkedState: true });
with (regMarksGroup) {
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Option:" });
with (dialogColumns.add()) {
staticTexts.add({ staticLabel: "inner radius:" });
staticTexts.add({ staticLabel: "outer radius:" });
staticTexts.add({ staticLabel: "offset:" });
}
with (dialogColumns.add()) {
var regMarkInnerRadiusField = measurementEditboxes.add({ editValue: (2.8345 * 1), editUnits: MeasurementUnits.millimeters });
var regMarkOuterRadiusField = measurementEditboxes.add({ editValue: (2.8345 * 1.5), editUnits: MeasurementUnits.millimeters });
var regMarkOffsetField = measurementEditboxes.add({ editValue: 0, editUnits: MeasurementUnits.millimeters });
}
}
}
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Range for drawing:" });
var rangeButtons = radiobuttonGroups.add();
with (rangeButtons) {
radiobuttonControls.add({ staticLabel: "Every object", checkedState: true });
radiobuttonControls.add({ staticLabel: "whole selection" });
}
}
}
}
// show the dialog
var result = dialog.show();
//Get the values from the dialog box.从对话框获取
var doCropMarks = cropMarksGroup.checkedState;
var doRegMarks = regMarksGroup.checkedState;
var cropMarkLength = cropMarkLengthField.editValue;
var cropMarkOffset = cropMarkOffsetField.editValue;
var cropMarkWidth = cropMarkWidthField.editValue;
var regMarkInnerRadius = regMarkInnerRadiusField.editValue;
var regMarkOuterRadius = regMarkOuterRadiusField.editValue;
var regMarkOffset = regMarkOffsetField.editValue;
//书脊和勒口
var spineWidth = spineWidthField.editValue;
var mouthWidth = mouthWidthField.editValue;
var range = rangeButtons.selectedButton;
dialog.destroy();
if (!result)
// user cancelled
return;
//"||" is logical OR in JavaScript.
if (!doCropMarks && !doRegMarks)
return alert("No printers marks were selected.");
//Create a layer to hold the printers marks (if it does not already exist).
var layer = doc.layers.item("cropMarks");
if (!layer.isValid)
layer = doc.layers.add({ name: "cropMarks" });
//Get references to the Registration color and the None swatch.
var registrationColor = doc.colors.item("Registration");
var noneSwatch = doc.swatches.item("None");
// these are the bounds we will add cropmarks to
var allBounds = [];
// get bounds of selection
var items = doc.selection;
for (var i = 0; i < items.length; i++)
allBounds.push(items[i].visibleBounds);
if (range === 1)
// combine all the item bounds into one bound
allBounds = [combineBounds(allBounds)];
// loop over the bounds and draw the marks
for (var i = 0; i < allBounds.length; i++) {
var bounds = allBounds[i];
if (doCropMarks == true) {
drawCropMarks(bounds, doc);
}
if (doRegMarks == true) {
drawRegMarks(bounds, doc);
}
}
function drawCropMarks(bounds, group) {
var x1 = bounds[1],
y1 = bounds[0],
x2 = bounds[3],
y2 = bounds[2];
var props = {
filled: false,
stroked: true,
strokeColor: registrationColor,
strokeWeight: cropMarkWidth,
};
//Create a group for the marks (we need)
var tmp1 = doc.graphicLines.add();
var tmp2 = doc.graphicLines.add();
var group = doc.layoutWindows[0].activePage.groups.add([tmp1, tmp2], layer);
// dublove, this is where you are currently working
var xCenterA = x1 + ((x2 - x1) / 2);
var yCenterA = y1 + ((y2 - y1) / 2);
var spineLeft = xCenterA - (20 / 2);
var spineRight = xCenterA + (20 / 2);
//Drawmouth 画勒口线
drawGraphicLine([x1 + mouthWidth, y1], [x1 + mouthWidth, y1 - cropMarkLength], group, props);
drawGraphicLine([x1 + mouthWidth, y2], [x1 + mouthWidth, y2 + cropMarkLength], group, props);
//Upper left crop mark pair.左上角
drawGraphicLine([x1, y1], [x1 - cropMarkLength, y1], group, props);
drawGraphicLine([x1, y1 + cropMarkOffset], [x1 - cropMarkLength, y1 + cropMarkOffset], group, props);
drawGraphicLine([x1, y1], [x1, y1 - cropMarkLength], group, props);
drawGraphicLine([x1 + cropMarkOffset, y1], [x1 + cropMarkOffset, y1 - cropMarkLength], group, props);
//Lower left crop mark pair.左下角
drawGraphicLine([x2, y1], [x2 + cropMarkLength, y1], group, props);
drawGraphicLine([x2 - cropMarkOffset + cropMarkOffset, y1 + cropMarkOffset], [x2 - cropMarkOffset + cropMarkOffset + cropMarkLength, y1 + cropMarkOffset], group, props);
drawGraphicLine([x2, y1], [x2, y1 - cropMarkLength], group, props);
drawGraphicLine([x2 - cropMarkOffset, y1], [x2 - cropMarkOffset, y1 - cropMarkLength], group, props);
//Upper right crop mark pair.右上角
drawGraphicLine([x1, y2], [x1 - cropMarkLength, y2], group, props);
drawGraphicLine([x1, y2 - cropMarkOffset], [x1 - cropMarkLength, y2 - cropMarkOffset], group, props);
drawGraphicLine([x1, y2], [x1, y2 + cropMarkLength], group, props);
drawGraphicLine([x1 + cropMarkOffset, y2], [x1 + cropMarkOffset, y2 + cropMarkLength], group, props);
//Lower right crop mark pair.右下角
drawGraphicLine([x2, y2], [x2 + cropMarkLength, y2], group, props);
drawGraphicLine([x2, y2 - cropMarkOffset], [x2 + cropMarkLength, y2 - cropMarkOffset], group, props);
drawGraphicLine([x2, y2], [x2, y2 + cropMarkLength], group, props);
drawGraphicLine([x2 - cropMarkOffset, y2], [x2 - cropMarkOffset, y2 + cropMarkLength], group, props);
// cleanup the temporary items in the group
tmp2.remove();
tmp1.remove();
return group;
};
//画圆十字
function drawRegMarks(bounds, container) {
var x1 = bounds[1],
y1 = bounds[0],
x2 = bounds[3],
y2 = bounds[2];
var cx = x1 + ((x2 - x1) / 2);
var cy = y1 + ((y2 - y1) / 2);
var offset = regMarkOffset + regMarkOuterRadius;
var props = {
filled: false,
stroked: true,
strokeColor: registrationColor,
strokeWeight: cropMarkWidth,
};
var registrationTargetItems = [
//Top registration target.上方圆
drawRegistrationTarget([cx, y1 - offset], regMarkInnerRadius, regMarkOuterRadius, container, props),
//Bottom registration target.下方圆
drawRegistrationTarget([cx, y2 + offset], regMarkInnerRadius, regMarkOuterRadius, container, props),
//Left registration target.左侧圆
drawRegistrationTarget([x1 - offset, cy], regMarkInnerRadius, regMarkOuterRadius, container, props),
//Right registration target.右侧圆
drawRegistrationTarget([x2 + offset, cy], regMarkInnerRadius, regMarkOuterRadius, container, props),
];
var group = container.groups.add(registrationTargetItems);
group.itemLayer = layer;
return group;
};
};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add Cropmarks');
/**
* Returns a registration target symbol.
* @author m1b
* @version 2025-03-28
* @param {Array<Number>} center - the center of the target [x, y].
* @param {Number} radius - the radius of the circle, in points.
* @param {Number} lineSize - the length of the lines from the center, in points.
* @param {Document|Page|Spread} container - the place to draw the line
* @param {Object} [props] - properties to apply to the new line (default: no properties)
* @returns {Group}
*/
function drawRegistrationTarget(center, circleRadius, lineSize, container, props) {
props = props || {};
var parts = [],
x = center[0],
y = center[1];
// lines
parts.push(drawGraphicLine([x - lineSize, y], [x + lineSize, y], container, props))
parts.push(drawGraphicLine([x, y - lineSize], [x, y + lineSize], container, props))
// circle
parts.push(drawCircle(center, circleRadius, container, props))
// return group
return container.groups.add(parts);
};
/**
* Returns a new circle.
* @author m1b
* @version 2025-03-28
* @param {Array<Number>} center - the center of the circle [x, y].
* @param {Number} radius - the radius of the circle, in points.
* @param {Document|Page|Spread} container - the place to draw the line
* @param {Object} [props] - properties to apply to the new line (default: no properties)
* @returns {Oval}
*/
function drawCircle(center, radius, container, props) {
var circle = container.ovals.add();
circle.geometricBounds = [center[1] - radius, center[0] - radius, center[1] + radius, center[0] + radius];
circle.properties = props || {};
return circle;
};
/**
* Returns a new graphic line.
* @author m1b
* @version 2025-03-28
* @param {Array<Number>} p0 - the first point [x, y].
* @param {Array<Number>} p1 - the second point [x, y].
* @param {Document|Page|Spread} container - the place to draw the line
* @param {Object} [props] - properties to apply to the new line (default: no properties)
* @returns {GraphicLine}
*/
function drawGraphicLine(p0, p1, container, props) {
var newLine = container.graphicLines.add();
newLine.paths.item(0).pathPoints.item(0).anchor = p0;
newLine.paths.item(0).pathPoints.item(1).anchor = p1;
newLine.properties = props || {};
return newLine;
};
/**
* Returns the combined bounds of all bounds supplied.
* Works with Illustrator or Indesign bounds.
* @author m1b
* @version 2024-03-09
* @param {Array<bounds>} boundsArray - an array of bounds [L, T, R, B] or [T, L , B, R].
* @returns {bounds?} - the combined bounds.
*/
function combineBounds(boundsArray) {
var combinedBounds = boundsArray[0].slice(),
comparator;
if (/indesign/i.test(app.name))
comparator = [Math.min, Math.min, Math.max, Math.max];
else if (/illustrator/i.test(app.name))
comparator = [Math.min, Math.max, Math.max, Math.min];
// iterate through the rest of the bounds
for (var i = 1; i < boundsArray.length; i++) {
var bounds = boundsArray[i];
combinedBounds = [
comparator[0](combinedBounds[0], bounds[0]),
comparator[1](combinedBounds[1], bounds[1]),
comparator[2](combinedBounds[2], bounds[2]),
comparator[3](combinedBounds[3], bounds[3]),
];
}
return combinedBounds;
};
... View more
Mar 27, 2025
06:27 PM
Even sillier, I *did* look in /System/Library but completely missed the more obvious /Library right next to it. They are just places I almost never visit.
... View more
Mar 27, 2025
06:07 PM
Hi @dublove the variable is out of scope. Roughly speaking, a variable declared in a Function 1 cannot be accessed from Function 2 unless (a) the variable is declared as a global—not good practice as a rule, or (b) the Function 2 is declared inside Function 1, or (c) the variable is passed to Function 2 as a parameter.
To fix your code, I just moved several functions up into the myDisplayDialog function like option (b) above.
There are cleaner ways to do it, but this was quick. If you are keen to learn my preferred approach, see my other scripts where I use a `settings` variable and a `ui` function. This structure allows me to easily run the script without the UI, for example.
- Mark
/* CropMarks.jsx
Draws crop and/or registration marks around the selected object or objects.
For more on InDesign scripting, go to http://www.adobe.com/products/indesign/scripting.html
or visit the InDesign Scripting User to User forum at http://www.adobeforums.com
Modified by dublove
*/
function main() {
if (app.documents.length === 0)
return alert("Ple请打开一个文档,选择一个物体再试,呵呵");
if (app.selection.length == 0)
return alert("请选择一个物体再试,呵呵.");
switch (app.selection[0].constructor.name) {
case "Rectangle":
case "Oval":
case "Polygon":
case "GraphicLine":
case "Group":
case "TextFrame":
case "Button":
myDisplayDialog();
break;
default:
alert("选择一个页面消息再试.");
break;
}
function myDisplayDialog() {
var myDialog = app.dialogs.add({ name: "DrawCropMarks" });
with (myDialog) {
with (dialogColumns.add()) {
var myCropMarksGroup = enablingGroups.add({ staticLabel: "CropMarks", checkedState: true });
with (myCropMarksGroup) {
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Option:" });
with (dialogColumns.add()) {
staticTexts.add({ staticLabel: "lengths:" });
staticTexts.add({ staticLabel: "offset:" });
staticTexts.add({ staticLabel: "Thickness:" });
staticTexts.add({ staticLabel: "Spine:" });
staticTexts.add({ staticLabel: "Mouth:" });
}
with (dialogColumns.add()) {
//看到的界面单位是毫米,运算前的值为点,所以要奖毫米折算为点(即,毫米值乘于2.8345)进行
var myCropMarkLengthField = measurementEditboxes.add({ editValue: (2.8345 * 3), editUnits: MeasurementUnits.millimeters });
var myCropMarkOffsetField = measurementEditboxes.add({ editValue: (2.8345 * 3), editUnits: MeasurementUnits.millimeters });
var myCropMarkWidthField = measurementEditboxes.add({ editValue: (2.8345 * 0.1), editUnits: MeasurementUnits.millimeters });
//新增 书脊 勒口
var mySpineWidthField = measurementEditboxes.add({ editValue: (2.8345 * 20), editUnits: MeasurementUnits.millimeters });
var myMouthWidthField = measurementEditboxes.add({ editValue: (2.8345 * 83), editUnits: MeasurementUnits.millimeters });
}
}
}
var myRegMarksGroup = enablingGroups.add({ staticLabel: "alignment mark", checkedState: true });
with (myRegMarksGroup) {
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Option:" });
with (dialogColumns.add()) {
staticTexts.add({ staticLabel: "inner radius:" });
staticTexts.add({ staticLabel: "outer radius:" });
staticTexts.add({ staticLabel: "offset:" });
}
with (dialogColumns.add()) {
var myRegMarkInnerRadiusField = measurementEditboxes.add({ editValue: (2.8345 * 1), editUnits: MeasurementUnits.millimeters });
var myRegMarkOuterRadiusField = measurementEditboxes.add({ editValue: (2.8345 * 1.5), editUnits: MeasurementUnits.millimeters });
var myRegMarkOffsetField = measurementEditboxes.add({ editValue: 0, editUnits: MeasurementUnits.millimeters });
}
}
}
with (borderPanels.add()) {
staticTexts.add({ staticLabel: "Range for drawing:" });
var myRangeButtons = radiobuttonGroups.add();
with (myRangeButtons) {
radiobuttonControls.add({ staticLabel: "Every object", checkedState: true });
radiobuttonControls.add({ staticLabel: "whole selection" });
}
}
}
}
var myReturn = myDialog.show();
//Get the values from the dialog box.从对话框获取
var myDoCropMarks = myCropMarksGroup.checkedState;
var myDoRegMarks = myRegMarksGroup.checkedState;
var myCropMarkLength = myCropMarkLengthField.editValue;
var myCropMarkOffset = myCropMarkOffsetField.editValue;
var myCropMarkWidth = myCropMarkWidthField.editValue;
var myRegMarkInnerRadius = myRegMarkInnerRadiusField.editValue;
var myRegMarkOuterRadius = myRegMarkOuterRadiusField.editValue;
var myRegMarkOffset = myRegMarkOffsetField.editValue;
//书脊和勒口
var mySpineWidth = mySpineWidthField.editValue;
var myMouthWidth = myMouthWidthField.editValue;
var myRange = myRangeButtons.selectedButton;
myDialog.destroy();
if (!myReturn)
return;
//"||" is logical OR in JavaScript.
if (!myDoCropMarks && !myDoRegMarks)
return alert("No printers marks were selected.");
myDrawPrintersMarks(myRange, myDoCropMarks, myDoRegMarks, myCropMarkLength, myCropMarkOffset, myCropMarkWidth, myRegMarkInnerRadius, myRegMarkOuterRadius, myRegMarkOffset);
// dublove, keep all these functions in the same scope (inside the myDisplayDialog function):
function myDrawPrintersMarks(myRange, myDoCropMarks, myDoRegMarks, myCropMarkLength, myCropMarkOffset, myCropMarkWidth, myRegMarkInnerRadius, myRegMarkOuterRadius, myRegMarkOffset) {
var myBounds, myX1, myY1, myX2, myY2, myObject;
var myDocument = app.activeDocument;
var myOldRulerOrigin = myDocument.viewPreferences.rulerOrigin;
myDocument.viewPreferences.rulerOrigin = RulerOrigin.spreadOrigin;
//Save the current measurement units.
//var oldMeasurementUnits=myDocument.viewPreferences.horizontalMeasurementUnits
//因有些函数默认计算单位为点,所以运算前要改为点,运算完成后可改回习惯毫米
var oldMeasurementUnits = myDocument.viewPreferences.horizontalMeasurementUnits
myDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.points;
myDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.points;
//Create a layer to hold the printers marks (if it does not already exist).
var myLayer = myDocument.layers.item("myCropMarks");
try {
myLayerName = myLayer.name;
}
catch (myError) {
var myLayer = myDocument.layers.add({ name: "myCropMarks" });
}
//Get references to the Registration color and the None swatch.
var myRegistrationColor = myDocument.colors.item("Registration");
var myNoneSwatch = myDocument.swatches.item("None");
//Process the objects in the selection.
myBounds = myDocument.selection[0].visibleBounds;
for (var myCounter = 0; myCounter < myDocument.selection.length; myCounter++) {
myObject = myDocument.selection[myCounter];
myBounds = myObject.visibleBounds;
//Set up some initial bounding box values.
if ((myRange != 0) && (myCounter == 0)) {
myX1 = myBounds[1];
myY1 = myBounds[0];
myX2 = myBounds[3];
myY2 = myBounds[2];
}
if (myRange == 0) {
if (myDoCropMarks == true) {
myDrawCropMarks(myBounds[1], myBounds[0], myBounds[3], myBounds[2], myCropMarkLength, myCropMarkOffset, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
if (myDoRegMarks == true) {
myDrawRegMarks(myBounds[1], myBounds[0], myBounds[3], myBounds[2], myRegMarkOffset, myRegMarkInnerRadius, myRegMarkOuterRadius, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
}
else {
//Compare the bounds values to the stored bounds.
//If a given bounds value is less than (for x1 and y1) or
//greater than (for x2 and y2) the stored value,
//then replace the stored value with the bounds value.
if (myBounds[0] < myY1) {
myY1 = myBounds[0];
}
if (myBounds[1] < myX1) {
myX1 = myBounds[1];
}
if (myBounds[2] > myY2) {
myY2 = myBounds[2];
}
if (myBounds[3] > myX2) {
myX2 = myBounds[3];
}
}
}
if (myRange != 0) {
if (myDoCropMarks == true) {
myDrawCropMarks(myX1, myY1, myX2, myY2, myCropMarkLength, myCropMarkOffset, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
if (myDoRegMarks == true) {
myDrawRegMarks(myX1, myY1, myX2, myY2, myRegMarkOffset, myRegMarkInnerRadius, myRegMarkOuterRadius, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
}
myDocument.viewPreferences.rulerOrigin = myOldRulerOrigin;
//Set the measurement units back to their original state.
//运算完成,将标尺单位改为习惯毫米
myDocument.viewPreferences.horizontalMeasurementUnits = oldMeasurementUnits;
myDocument.viewPreferences.verticalMeasurementUnits = oldMeasurementUnits;
}
function myDrawCropMarks(myX1, myY1, myX2, myY2, myCropMarkLength, myCropMarkOffset, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer) {
var myXCenterA = myX1 + ((myX2 - myX1) / 2);
var myYCenterA = myY1 + ((myY2 - myY1) / 2);
var mySpineLeft = myXCenterA - (20 / 2);
var mySpineRight = myXCenterA + (20 / 2);
//Drawspinee画书脊线 Test--------,Temporarily replace it with a constant
//myDrawLine([myY1, myXCenterA -(20/2), myY1-(myCropMarkLength), myXCenterA -(20/2)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//myDrawLine([myY1, myXCenterA +(20/2), myY1-(myCropMarkLength), myXCenterA +(20/2)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//myDrawLine([myY2, myXCenterA -(20/2), myY2+(myCropMarkLength), myXCenterA -(20/2)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//myDrawLine([myY2, myXCenterA +(20/2), myY2+(myCropMarkLength), myXCenterA +(20/2)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Drawmouth 画勒口线
myDrawLine([myY1, myX1 + (myMouthWidth), myY1 - (myCropMarkLength), myX1 + (myMouthWidth)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1, myXCenterA + (20 / 2), myY1 - (myCropMarkLength), myXCenterA + (20 / 2)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Upper left crop mark pair.左上角
myDrawLine([myY1, myX1, myY1, myX1 - (myCropMarkLength)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1 + myCropMarkOffset, myX1, myY1 + myCropMarkOffset, myX1 - (myCropMarkLength)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1, myX1, myY1 - (myCropMarkLength), myX1], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1, myX1 + myCropMarkOffset, myY1 - (myCropMarkLength), myX1 + myCropMarkOffset], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Lower left crop mark pair.左下角
myDrawLine([myY2, myX1, myY2, myX1 - (myCropMarkLength)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2 - myCropMarkOffset, myX1, myY2 - myCropMarkOffset, myX1 - (myCropMarkLength)], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2, myX1, myY2 + myCropMarkLength, myX1], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2, myX1 + myCropMarkOffset, myY2 + myCropMarkLength, myX1 + myCropMarkOffset], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Upper right crop mark pair.右上角
myDrawLine([myY1, myX2, myY1, myX2 + myCropMarkLength], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1 + myCropMarkOffset, myX2 - myCropMarkOffset + myCropMarkOffset, myY1 + myCropMarkOffset, myX2 - myCropMarkOffset + myCropMarkOffset + myCropMarkLength], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1, myX2, myY1 - (myCropMarkLength), myX2], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY1, myX2 - myCropMarkOffset, myY1 - (myCropMarkLength), myX2 - myCropMarkOffset], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Lower rigth crop mark pair.右下角
myDrawLine([myY2, myX2, myY2, myX2 + myCropMarkLength], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2 - myCropMarkOffset, myX2, myY2 - myCropMarkOffset, myX2 + myCropMarkLength], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2, myX2, myY2 + myCropMarkLength, myX2], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myDrawLine([myY2, myX2 - myCropMarkOffset, myY2 + myCropMarkLength, myX2 - myCropMarkOffset], myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
//画圆十字
function myDrawRegMarks(myX1, myY1, myX2, myY2, myRegMarkOffset, myRegMarkInnerRadius, myRegMarkOuterRadius, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer) {
var myBounds
var myXCenter = myX1 + ((myX2 - myX1) / 2);
var myYCenter = myY1 + ((myY2 - myY1) / 2);
var myTargetCenter = myRegMarkOffset + (myRegMarkOuterRadius);
//Top registration target.上方圆
myBounds = [myY1 - (myTargetCenter + myRegMarkInnerRadius), myXCenter - myRegMarkInnerRadius, (myY1 - myTargetCenter) + myRegMarkInnerRadius, myXCenter + myRegMarkInnerRadius];
myDrawTarget(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myY1 - (myTargetCenter + myRegMarkOuterRadius), myXCenter, (myY1 - myTargetCenter) + myRegMarkOuterRadius, myXCenter]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myY1 - myTargetCenter, myXCenter - myRegMarkOuterRadius, myY1 - myTargetCenter, myXCenter + myRegMarkOuterRadius]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Left registration target.左侧圆
myBounds = [myYCenter - myRegMarkInnerRadius, myX1 - (myTargetCenter + myRegMarkInnerRadius), myYCenter + myRegMarkInnerRadius, (myX1 - myTargetCenter) + myRegMarkInnerRadius];
myDrawTarget(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myYCenter, myX1 - (myTargetCenter + myRegMarkOuterRadius), myYCenter, myX1 - myRegMarkOffset]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myYCenter - myRegMarkOuterRadius, myX1 - myTargetCenter, myYCenter + myRegMarkOuterRadius, myX1 - myTargetCenter]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Bottom registration target.下方圆
myBounds = [myY2 + (myTargetCenter - myRegMarkInnerRadius), myXCenter - myRegMarkInnerRadius, myY2 + myTargetCenter + myRegMarkInnerRadius, myXCenter + myRegMarkInnerRadius];
myDrawTarget(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myY2 + myRegMarkOffset, myXCenter, myY2 + myTargetCenter + myRegMarkOuterRadius, myXCenter]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myY2 + myTargetCenter, myXCenter - myRegMarkOuterRadius, myY2 + myTargetCenter, myXCenter + myRegMarkOuterRadius]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
//Right registration target.右侧圆
myBounds = [myYCenter - myRegMarkInnerRadius, myX2 + (myTargetCenter - myRegMarkInnerRadius), myYCenter + myRegMarkInnerRadius, myX2 + myTargetCenter + myRegMarkInnerRadius];
myDrawTarget(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myYCenter, myX2 + myRegMarkOffset, myYCenter, myX2 + myTargetCenter + myRegMarkOuterRadius]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
myBounds = [myYCenter - myRegMarkOuterRadius, myX2 + myTargetCenter, myYCenter + myRegMarkOuterRadius, myX2 + myTargetCenter]
myDrawLine(myBounds, myCropMarkWidth, myRegistrationColor, myNoneSwatch, myLayer);
}
function myDrawLine(myBounds, myStrokeWeight, myRegistrationColor, myNoneSwatch, myLayer) {
app.activeWindow.activeSpread.graphicLines.add(myLayer, undefined, undefined, { strokeWeight: myStrokeWeight, fillColor: myNoneSwatch, strokeColor: myRegistrationColor, geometricBounds: myBounds })
}
function myDrawTarget(myBounds, myStrokeWeight, myRegistrationColor, myNoneSwatch, myLayer) {
app.activeWindow.activeSpread.ovals.add(myLayer, undefined, undefined, { strokeWeight: myStrokeWeight, fillColor: myNoneSwatch, strokeColor: myRegistrationColor, geometricBounds: myBounds })
}
}
};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add Cropmarks');
Edit 2025-03-28: typo (removed erroneous reference to `settings`)
... View more
Mar 27, 2025
05:31 PM
Thank you for setting me straight @Ton Frederiks! I didn't read the path carefully and assumed it was in my local Library. I see it now. It's actually an interesting folder to poke around in.
- Mark
... View more
Mar 26, 2025
02:29 AM
1 Upvote
Thanks @jk-d6 that's good info.
... View more
Mar 26, 2025
12:34 AM
Thanks @Manan Joshi so strange that I don't have that folder. Oh well. @default11h12xm5yo8m can you see the folder that Manan showed us? Perhaps you could remove the buggy 'photoshop_v2025.jsx' file? Or post it here somehow?
... View more
Mar 26, 2025
12:29 AM
1 Upvote
@Eugene Tyson Perfect! I'll mark this as correct. 🙂
... View more
Mar 25, 2025
11:30 PM
Interesting! @Manan Joshi I don't have that folder at all. Do you have a "photoshop_2025.jsx" file?
... View more
Mar 25, 2025
09:43 PM
@punit_9859 for questions about Photoshop scripting please ask on the Photoshop forum.
By the way, did you solve the "msising Brace" problem you reported here?
... View more
Mar 25, 2025
09:26 PM
1 Upvote
Hi @Robert at ID-Tasker I can confirm this bug on MacOS 15.3.2, Indesign 20.2.
- Mark
P.S. is there any advantage in turning off the autoGrow. In my quick tests it seemed to work just as well (and doesn't trigger the bug, by the way) when I just turn autoGrow on first, then set the height:
app.activeDocument.stories.everyItem().tables.everyItem().rows.everyItem().autoGrow = true;
app.activeDocument.stories.everyItem().tables.everyItem().rows.everyItem().height = 5;
... View more
Mar 25, 2025
09:16 PM
Hey @Jami Murphy any chance you could post that photoshop_2025.jsx file? The path is in the error dialog above. You can change it to .txt to bypass the forum's restrictions on file types if necessary.
- Mark
... View more
Mar 25, 2025
09:13 PM
Hi @Manan Joshi yes I'm also intrigued about what the script is, and I'd like to see it, but also intrigued that some users have the "Startup Scripts" folder installed, even though—as a user said on the Illustrator thread—they'd never used scripts.
- Mark
... View more
Mar 25, 2025
07:45 PM
An additional note is that I am on MacOS also, but I don't have that folder "Startup Scripts CC" at all. Maybe you could move that folder to your desktop and restart, and see if that makes a difference.
- Mark
... View more
Mar 25, 2025
06:41 PM
Users in the Indesign forum have reported the same problem with Indesign. It might be a buggy script installed as part of the latest Photoshop Beta. Do any of you guys have the Photoshop Beta installed? Or recently downloaded Photoshop?
- Mark
... View more
Mar 25, 2025
06:40 PM
2 Upvotes
Hi @default11h12xm5yo8m this does seem to be a somewhat widespread issue. We have Illustrator users reporting the same error.
@HARSHIKA_VERMA, @Sanyam Talwar could either of you help us get this information to the right person? Might be a buggy script as part of the latest Photoshop beta?
- Mark
... View more
Mar 25, 2025
05:53 PM
Yes @Robert at ID-Tasker that is a handy trick. Setting the minimumHeight will give the same effect, I think.
... View more