英文:
Indesign - Error 27 "Stack overrun" with app.doScript
问题
I see you've provided a JavaScript script for Adobe InDesign. It appears to be related to automating the process of placing images into an InDesign document based on barcode information. If you have any specific questions or need assistance with a particular part of the script, please let me know.
英文:
I'm trying to automate most of my workplace tasks, but I'm somehow stuck.
Part of job consists in placing various photos into an InDesign document for nesting them and creating pdfs to be printed on special custom machines.
Each photo is accompanied by a paper order marked with a order number ranging from 5 to 8 digits and a barcode containing this order number and other information.
The filename of the images contains the order number and I have to place them manually.
Since it's a very time consuming task I thought I'd use a barcode scanner to enter the order barcode (deleting the information I don't need and keeping only the order number) and search inside the photo folder the corresponding image to insert it automatically.
To make it faster I thought of continuously restarting the script in order to insert them one after the other, but after inserting exactly 39 images, this gives me error 27: Stack overrun.
Is there any way to fix this error? In case I have to rewrite the whole script, how do you recommend to do it?
This is the script:
#target "InDesign"
#targetengine "session"
if (app.documents.length == 0) {MyImages
alert ("Open a document first");
exit ();
}
// I've made some research on internet and apparently some user solved the problem increasing the memCache, but it doesn't work in my case
$.memCache = 9999999999;
app.scriptPreferences.enableRedraw = false;
var MyDoc = app.activeDocument;
MyDoc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.millimeters;
MyDoc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.millimeters;
app.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
MyDoc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
MyDoc.zeroPoint = [0,0];
var MyFolder, MyImages, ImgNumber;
// RestartScript is used to prevent the script from restarting with app.doScript (line 70) if the cancel button is pressed
var RestartScript = 0;
var MyPanel = new Window ("dialog", "Enter the barcode");
var MyText = MyPanel.add ("edittext");
MyText.preferredSize.width = 150;
MyText.onChanging = function () {
MyText.text = MyText.text.replace (/[^0-9]/g, "");
// This part allows the script to continue automatically once the barcode scanner enters the code which is 15 characters long
if (MyText.text.length >= 15) {
BarcodeConversion ();
MyPanel.close ();
}
}
// The EventListener allows a manual insertion of the image number (if the barcode is not present on the order)
MyText.addEventListener ("keydown", function (KeyEvent) {
if (KeyEvent.keyName == "Enter") {
if (MyText.text != "") {
ImgNumber = MyText.text;
MyPanel.close ();
}
}
});
// The focus is on the edittext for practical purposes
MyText.active = true;
var Browse = MyPanel.add ("button", undefined, "Browse");
Browse.onClick = function () {
MyFolder = Folder.selectDialog ("Select a folder", " ");
MyImages = MyFolder.getFiles (/.+\.(?:gif|jpe?g|eps|tiff?|psd|pdf|bmp|png)$/i);
if (MyImages.length <= 0) {
alert ("There are no images in this folder");
return;
}
// This is for focusing on the edittext automatically after clicking the browse button, but it doesn't work (I don't know why)
MyText.active = true;
}
var Cancel = MyPanel.add ("button", undefined, "Cancel");
Cancel.onClick = function () {
MyPanel.close ();
}
MyPanel.show ();
if (ImgNumber != undefined) {
Search ();
}
// I'm using app.doScript to restart the same script and automatically insert multiple images in a continuous way (I've tried with MyPanel.show() instead of this to reopen the input panel but it doesn't display well)
// This is what causes the stack overrun error
if (RestartScript == 1) {
app.doScript (new File (app.activeScript.parent.fsName + "\\" + app.activeScript.name) ,ScriptLanguage.JAVASCRIPT);
}
function BarcodeConversion () {
if (MyFolder == undefined) {
alert ("Folder not selected");
MyText.text = "";
return;
}
// Here I use slice to remove the part of the barcode I don't need, obtaining the order's number
ImgNumber = MyText.text.slice (4, 12);
}
function Search () {
// In this function I'm placing all the images with the filename who correspond to the order's number in an array (in case I have multiple images with the same number)
var ImgFound = [];
for (var a = 0; a < MyImages.length; a++) {
if (MyImages[a].name.toLowerCase ().indexOf (ImgNumber.toString ()) != -1) {
ImgFound.push (MyImages[a]);
// If there are more images with the same number an alert is triggered and the manual selection is done with openDlg (with the * wildcard character as I work on windows )
if (ImgFound.length > 1) {
// A sound alert is triggered, but the volume is too low and doesn't work properly on windows 11 (if someone kwow how to do it in a different way, feel free to share the method)
beep ();
alert ("There are multiple images with the number " + ImgNumber);
var ManualSelection = (File (MyFolder + "/*" + ImgNumber + "*")).openDlg ("Place", undefined, true);
if (ManualSelection == null) {
Reset ();
return;
}
ImgFound = [];
for (var b = 0; b < ManualSelection.length; b++) {
ImgFound.push (ManualSelection[b]);
}
break;
}
}
}
// Here i place all the images from the array in the current page and center them
for (var c = 0; c < ImgFound.length; c++) {
app.activeWindow.activePage.place (ImgFound[c]);
MyDoc.align (app.activeWindow.activePage.rectangles[0], AlignOptions.VERTICAL_CENTERS, AlignDistributeBounds.PAGE_BOUNDS);
MyDoc.align (app.activeWindow.activePage.rectangles[0], AlignOptions.HORIZONTAL_CENTERS, AlignDistributeBounds.PAGE_BOUNDS);
}
if (ImgFound == 0) {
alert ("Image " + ImgNumber + " not present");
}
Reset ();
}
function Reset () {
// This function serves to reset the variables to avoid conflicts / errors
ImgNumber = undefined;
ImgFound = 0;
RestartScript = 1;
}
UPDATE
After some testing, I updated the script with the palette method as Yuri suggested.
#target "InDesign"
#targetengine "session"
if (app.documents.length == 0) {
beep ();
alert ("Open a document first", " ");
exit ();
}
app.scriptPreferences.enableRedraw = false;
var MyDoc = app.activeDocument;
MyDoc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.millimeters;
MyDoc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.millimeters;
app.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
MyDoc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
MyDoc.zeroPoint = [0,0];
var MyFolder, MyImages, ImgNumber;
var MyPanel = new Window ("palette", "Enter the barcode");
MyPanel.orientation = "column";
var Group1 = MyPanel.add ("group");
Group1.orientation = "row";
var MyPath = Group1.add ("statictext");
MyPath.preferredSize.width = 150;
if (MyFolder != undefined) {
MyPath.text = decodeURI (MyFolder);
}
var BrowseButton = Group1.add ("button", undefined, "Browse");
BrowseButton.onClick = function () {
MyFolder = Folder.selectDialog ("Select a folder");
if (MyFolder == null) {
MyFolder = null;
MyPath.text = "";
return;
}
MyImages = MyFolder.getFiles (/.+\.(?:gif|jpe?g|eps|tiff?|psd|pdf|bmp|png)$/i);
if (MyImages.length <= 0) {
beep ();
alert ("There are no images in the selected folder", " ");
return;
}
MyPath.text = decodeURI (MyFolder);
}
var Group2 = MyPanel.add ("group");
Group2.orientation = "row";
var MyText = Group2.add ("edittext");
MyText.preferredSize.width = 150;
MyText.onChanging = function () {
MyText.text = MyText.text.replace (/[^0-9]/g, "");
if (MyText.text.length >= 15) {
BarcodeConversion ();
}
}
MyText.addEventListener ("keydown", EnterEvent);
var CancelButton = Group2.add ("button", undefined, "Cancel");
CancelButton.onClick = function () {
MyPanel.close ();
}
MyText.active = true;
MyPanel.addEventListener ("keydown", EscapeEvent);
MyPanel.onClose = function () {
ImgNumber = undefined;
MyText.removeEventListener ("keydown", EnterEvent);
MyPanel.removeEventListener ("keydown", EscapeEvent);
}
MyPanel.show ();
function Warning () {
if (MyFolder == undefined) {
alert ("No folder selected", " ");
MyText.text = "";
return;
}
}
function EnterEvent (EventA) {
Warning ();
if (EventA.keyName === "Enter" && MyText.text != "") {
ImgNumber = MyText.text;
MyText.text = "";
Search ();
}
}
function EscapeEvent (EventB) {
if (EventB.keyName == "Escape") {
MyPanel.close ();
}
}
function BarcodeConversion () {
Warning ();
ImgNumber = MyText.text.slice (4, 12);
while (ImgNumber.match (new RegExp (/^\d/)) == 0) {
ImgNumber = ImgNumber.slice (1);
}
MyText.text = "";
if (ImgNumber != undefined) {
Search ();
}
}
function Search () {
var ImgFound = [];
for (var a = 0; a < MyImages.length; a++) {
if (MyImages[a].name.toLowerCase ().indexOf (ImgNumber.toString ()) != -1) {
ImgFound.push (MyImages[a]);
if (ImgFound.length > 1) {
beep ();
alert ("There are multiple images with the number " + ImgNumber, " ");
var ManualSelection = (File (MyFolder + "/*" + ImgNumber + "*")).openDlg ("Inserisci", undefined, true);
if (ManualSelection == null) {
ImgNumber = undefined;
return;
}
ImgFound = [];
for (var b = 0; b < ManualSelection.length; b++) {
ImgFound.push (ManualSelection[b]);
}
ManualSelection = undefined;
break;
}
}
}
if (ImgFound == 0) {
beep ();
alert ("Image " + ImgNumber + " not present", " ");
}
for (var c = 0; c < ImgFound.length; c++) {
app.activeWindow.activePage.place (ImgFound[c]);
MyDoc.align (app.activeWindow.activePage.rectangles[0], AlignOptions.VERTICAL_CENTERS, AlignDistributeBounds.PAGE_BOUNDS);
MyDoc.align (app.activeWindow.activePage.rectangles[0], AlignOptions.HORIZONTAL_CENTERS, AlignDistributeBounds.PAGE_BOUNDS);
}
ImgFound = [];
ImgNumber = undefined;
}
答案1
得分: 1
我会尝试使用调色板而不是对话框。以下是一个简短的示例,说明如何实现:
#target "InDesign"
#targetengine "session"
var palette = new Window('palette', '输入条形码');
palette.add('statictext', undefined, '文件夹:');
var folder = palette.add('edittext');
folder.text = 'd:\\temp';
folder.characters = 30;
palette.add('statictext', undefined, '文件:');
var file = palette.add('edittext');
file.characters = 30;
file.active = true;
file.onChanging = function() {
file.text = file.text.replace(/\D/g, '');
}
file.addEventListener('keydown', function(k) {
if (k.keyName == 'Enter' && file.text != '') {
place_image(folder.text, file.text);
file.text = '';
}
});
palette.addEventListener('keydown', function(k) {
if (k.keyName === 'Escape') {
palette.close();
// palette = null // 适用于Win CS6
}
});
palette.show();
// palette.onClose = function() { palette = null } // 适用于Win CS6
//------------------------------------------------------------------
function place_image(folder_name, file_name) {
var folder = Folder(folder_name);
var file = File(folder + '/' + file_name + '.jpg');
if (file.exists) app.activeWindow.activePage.place(file);
}
它将显示一个类似这样的调色板。您可以在第二个字段中输入文件名,按Enter键,它将从给定文件夹中使用该名称的jpeg图像放置到您的文档中。至少在我看来,对于这种情况,它运行良好。不需要使用doScript笨拙的技巧。您可以自己添加任何额外的功能。
英文:
I'd try to use a palette instead of a dialogue. Here is the short working example how it can be done:
#target "InDesign"
#targetengine "session"
var palette = new Window('palette', 'Enter the barcode');
palette.add('statictext', undefined, 'Folder:');
var folder = palette.add('edittext');
folder.text = 'd:\\temp';
folder.characters = 30;
palette.add('statictext', undefined, 'File:');
var file = palette.add('edittext');
file.characters = 30;
file.active = true;
file.onChanging = function() {
file.text = file.text.replace(/\D/g, '');
}
file.addEventListener('keydown', function(k) {
if (k.keyName == 'Enter' && file.text != '') {
place_image(folder.text, file.text);
file.text = '';
}
});
palette.addEventListener('keydown', function(k) {
if (k.keyName === 'Escape') {
palette.close();
// palette = null // for Win CS6
}
});
palette.show();
// palette.onClose = function() { palette = null } // for Win CS6
//------------------------------------------------------------------
function place_image(folder_name, file_name) {
var folder = Folder(folder_name);
var file = File(folder + '/' + file_name + '.jpg');
if (file.exists) app.activeWindow.activePage.place(file);
}
It will show you a palette like this:
You can input a file name into the second field, press Enter and it will place the jpeg image with this name from the given folder into your document.
As far as I can tell it works fine for this case. No need the doScript clumsy trick. At the very least it got me no errors after I placed about hundred images this way.
You can add any additional functions into it by yourself.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论