I don't have a lot of Indesign experience to say the least but I was asked to investigate if it was possible (using indesign server of scripting) to start a new document, apply a master spread page, insert some paragraphs and applying some paragraph styles.
The solution I came up is this
// define template
var indesignTemplate = new File("/e/mytemplate.indt");
// open the template
var doc = app.open(indesignTemplate);
// get master page
var masterPage = doc.masterSpreads.item("A-Master");
// get first page
var page = doc.pages.item(0);
// apply master page to our first page
page.appliedMaster = masterPage
// get paragraph style
var paragraphStyle = doc.paragraphStyles.item("_2.ondertitel_bladzijde");
for (var i = 0; i < masterPage.textFrames.length; i++) {
var textframe = masterPage.textFrames.item(i);
if (textframe.label === "flow") {
for (var x = 0; x < 5; x++) {
// insert another new paragraph
textframe.parentStory.insertionPoints.item(-1).contents = "Lorem ipsum dolor... \r\r";
}
for (var x = 0; x < textframe.paragraphs.length; x++) {
textframe.paragraphs.item(0).applyParagraphStyle(paragraphStyle);
}
}
}
//Save the document (fill in a valid file path).
doc.save(new File("/c/mybook.indd"));
// Save the document as an PDF
doc.exportFile(ExportFormat.pdfType, new File("/c/mybook.pdf"));
// close the document.
app.documents.item(0).close();
This works and can see my text when I comment out the applyParagraphStyle code.
From the moment that I try to apply a paragraphStyle the text gets hidden. When I then open the saved indd file in Indesign and command+shift click in the empty text frame, the text appears and I also see an extra layer appearing.
I also tried applying CharacterStyles in more or less the same way but that doesn't give any problems.
I assume that the problem lays in the fact that I'm may approaching this in the wrong way ?
In the end I came up with the following which fixed my problem. I don't know if i'm overengineering a bit or this is under the rules of the art.
var indesignTemplate = new File("/e/boek_nl.indt");
// open the template
var doc = app.open(indesignTemplate);
// get master page
var masterPage = doc.masterSpreads.item("A-Master");
// get first page
var page = doc.pages.item(0);
// apply master page to our first page
page.appliedMaster = masterPage
// get paragraph style
var paragraphStyle = doc.paragraphStyles.item("_2.ondertitel_bladzijde");
// get text frame
function getTextFrame(pageObj, frameName) {
var allItems = pageObj.appliedMaster.pageItems.everyItem().getElements();
for(var j=0;j<allItems.length;j++)
{
if(allItems[j].label === frameName) {
return allItems[j].override(pageObj);
}
}
var textFrame = getTextFrame(page, "flow")
// insert a paragraph 5 times
for (var x = 0; x < 5; x++) {
textFrame.parentStory.insertionPoints.item(-1).contents = "text \r\r";
}
// apply paragraph style
textFrame.paragraphs.item(0).applyParagraphStyle(paragraphStyle);
//Save the document (fill in a valid file path).
doc.save(new File("/c/boek_nl.indd"));
// Save the document as an PDF
doc.exportFile(ExportFormat.pdfType, new File("/c/boek_nl.pdf"));
// close the document.
app.documents.item(0).close();
You are applying master spread and then modifying it. I think the better approach would be to override text frames on the page. Try this:
// define template
var indesignTemplate = new File("/e/mytemplate.indt");
// open the template
var doc = app.open(indesignTemplate);
// get master page
var masterPage = doc.masterSpreads.item("A-Master");
// get first page
var page = doc.pages.item(0);
// apply master page to our first page
page.appliedMaster = masterPage; // you are missing closing semicolon here
// get paragraph style
var paragraphStyle = doc.paragraphStyles.item("_2.ondertitel_bladzijde");
for (var i = 0; i < page.textFrames.length; i++) {
var textframe = page.textFrames.item(i);
if (textframe.label === "flow") {
textframe.override(page);
for (var x = 0; x < 5; x++) {
// insert another new paragraph
textframe.parentStory.insertionPoints.item(-1).contents = "Lorem ipsum dolor... \r\r";
}
for (var x = 0; x < textframe.paragraphs.length; x++) {
textframe.paragraphs.item(0).applyParagraphStyle(paragraphStyle);
}
}
}
//Save the document (fill in a valid file path).
doc.save(new File("/c/mybook.indd"));
// Save the document as an PDF
If you have to change master spread for some reason, try to modify it first and then apply to the page.
Related
I'm trying to create a image RGB or CMYK using separate greyscale documents for each channel.
My current code copy all from greyscale document and paste in a new document creating a new layer for eachone. I don't want that, I want copy from each document and paste into eachone channels new document, same as manual way, selecting each channel and clicking Edit->paste->paste especial->paste in place.
// Loop to copy each separate channel into a new merged document
for (var doc_index = 0; doc_index < 3; doc_index++ ){
//Switch documents
app.activeDocument = split_channels[0];
// copy active layer from separate channel document
app.activeDocument.selection.selectAll();
app.activeDocument.selection.copy();
// close document whithout save
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
//select activeDocument
app.activeDocument = mergedDoc;
// reference to whole channels
//var channelIndex = doc_index;
var myChannels = app.activeDocument.channels;
// the channel must be visible to paste greyscale layer
myChannels[doc_index].visible= true;
// turn off the rest of channels
for (var secondaryIndex = 0; secondaryIndex < myChannels.length; secondaryIndex++) {
if (doc_index != secondaryIndex) {
myChannels[secondaryIndex].visible= false
}
}
//paste layer for each new document channel (no works correctly)
app.activeDocument.paste();
//reset the channel count after copy and close each document
var split_channels = app.documents;
}
thanks a lot for any suggestion
When copying the layer contents, you do want the layer contents to be visible so they are captured by the selection when you copy. When pasting, however, the destination of the selection is determined on the active layer/channel. Note that the document.activeChannels member requires an array when assigning to it, even if you are only wanting a single channel.
Also, be mindful of changing the underlying array while iterating over it (aka closing documents before exiting the for-loop). In my code below, I'm specifically iterating over a reference array, instead of the actual app.documents collection, to ensure the length of my array doesn't change when a document is closed.
For the sake of brevity, the following code assumes all documents are of equal dimensions/color modes/resolutions, the three source documents are flattened, and there's at least one pixel on each opposite extremity of the canvas to ensure the size/position is the same after pasting.
const colorMode = NewDocumentMode.RGB;
const numChannels = 3;
var srcDocs = new Array();
if (app.documents.length == numChannels) {
for (var i = 0; i < app.documents.length; i++)
srcDocs.push(app.documents[i]);
} else throw new Error("Channel merging for " + colorMode + " requires " + numChannels + " source documents.");
var doc = app.activeDocument;
var destDoc = app.documents.add(doc.width, doc.height, doc.resolution, "mergedDoc", colorMode);
var destChannels = new Array();
for (var i = 0; i < numChannels; i++)
destChannels.push(destDoc.channels[i]);
for (var i in srcDocs) {
// copy
app.activeDocument = srcDocs[i];
app.activeDocument.selection.selectAll();
app.activeDocument.selection.copy();
app.activeDocument.selection.deselect();
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
// pasta
app.activeDocument = destDoc;
var targetChannels = [destChannels[i]];
app.activeDocument.activeChannels = targetChannels;
app.activeDocument.paste();
}
app.activeDocument.selection.deselect();
app.activeDocument.activeChannels = destChannels;
I have an indesign document with multiple pages. each page has a linked pdf in it. each pdf has 3 layers within it and in order to turn these layers on or off, you have to right click, select Object Layer Options, and then manually turn on or off layers.
I would like to loop through all my pages and turn on a layer in the PDF using a script. i have been messing with graphicLayerOptions.graphicLayers but keep running into an error when telling it to turn the currentVisibilty=true;
var myDocument = app.activeDocument;
var docLength = myDocument.pages.length;
var myPages = myDocument.pages
for (var i = 0; i < docLength; i++) {
var labelPlaceholder = myDocument.allGraphics;
var labelArtwork = labelPlaceholder[0];
var artworkLayers = labelArtwork.graphicLayerOptions.graphicLayers;
artworkLayers.item("Die Copy").currentVisibility = true;
}
i got it working...l
var myDocument = app.activeDocument;
var docLength = myDocument.pages.length;
var myPages = myDocument.pages
for (var i = 0; i < docLength; i++) {
var labelPlaceholder = myPages[i].allGraphics;
var labelArtwork = labelPlaceholder[0];
var artworkLayers = labelArtwork.graphicLayerOptions.graphicLayers;
artworkLayers[0].currentVisibility = true;
}
Just in case. In InDesing (Illustrator, etc) you have two options to get an item from a collection.
By its number:
var layer = app.activeDocument.layers[0];
By its name:
var layer = app.activeDocument.layers.itemByName("Die Copy");
Later options is less reliable. Not all collections has this method. I don't know if it (PDF layers) is the case, though.
I'm trying to write a javascript what is searching for all of the links on the page, then it is adding them to the bottom, under the original content.
"Document.links" seems to do the finding part, it is also listing them, but they are not clickable. So I tried to add some html codes (startHref and endHref lines), which broke the whole thing of course.
My (non-working) script:
var links = document.links;
for(var i = 0; i < links.length; i++) {
var preLink = document.createTextNode("LINK: ");
var linkHref = document.createTextNode(links[i].href);
var lineBreak = document.createElement("br");
var startHref = document.createElement("a href="");
var endHref = document.createElement(""");
document.body.appendChild(preLink);
document.body.appendChild(startHref);
document.body.appendChild(linkHref);
document.body.appendChild(endHref);
document.body.appendChild(lineBreak);
}
If this will work I'd also like to have them listed with a number in front of each line (starting with 1 - could be set in the preLink part) - if not too hard to implement.
Also, is there a way to list not all of the links, but only those matching with something? Like only links with a specific domain. Thank you!
As you have already found out, you can get all links in a document with:
var links = document.links;
Now you have an HTMLCollection. You can iterate through it and display all links. For better layout you can put them in a paragraph (p). This would be the loop:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
p.appendChild(links[i]);
document.body.appendChild(p);
}
Now all links are appended at the end of the page, every link is on its own line and they are clickable. Please try this out.
EDIT: as of your comment, if I understand it right, you have just to put one additional line:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
// the following line is added
links[i].innerHTML = links[i].href;
p.appendChild(links[i]);
document.body.appendChild(p);
}
That line will simply replace the inner HTML of the link with its value for the attribute href.
EDIT:
The variable links just points to document.links. The existing links are therefore removed from their original position and appended to the end. If you try to create new links in the for loop, like document.createElement("a") you will create an endless loop, because you're iterating through all links in the document. You remember, the variable links is not a snapshot of document.links when created, but points to it.
You can work around this with creating an array:
var links = [];
// populate the array links
for (var j = 0; j < document.links.length; j++) {
links.push(document.links[j].cloneNode());
}
Now this is a snapshot of all links on the page. Every links is cloned and pushed to the array. Now run the for loop and the original links aren't removed.
If the original link was something like:
This is an example.
it will become:
http://example.com
But if you want just:
http://example.com
then you have to adapt the code:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
var a = document.createElement("a");
a.href = links[i].href;
a.text = links[i].href; // you can use text instead of innerHTML
p.appendChild(a);
document.body.appendChild(p);
}
If you want to style the output you can add classes like this:
p.classList.add("my-css-class");
I hope this helps you to achieve your goal.
okay i have come across a simple javascript code that will search all the hyperlinks in a page which works briliantly fast. the only problem is that the browser freezes when it tries to remake these links in a div, no error just as soon as i push the button the browser refuses to load. as you can see it gets the input from a form then searches every hyperlink for these terms then is supposed to populate a div with links but it doesn't. the code is as follows.
function search0(){
var lists = document.getElementsByTagName("a");
for (var i = 0; i < lists.length; i++) {
var output = lists[i];
var team1 = document.getElementById("search1").value;
var matchPos1 = output.innerHTML.search(team1);
if(matchPos1 != -1){
var team2 = document.getElementById("search2").value;
var matchPos2 = output.innerHTML.search(team2);
if(matchPos2 != -1){
var elem1 = document.createElement("a")
var styleattr=document.createAttribute("href");
styleattr.nodeValue=output;
elem1.setAttributeNode(styleattr);
var text1 = document.createTextNode(output.innerhtml);
elem1.appendChild(text1);
var parentdiv = document.getElementById("frame2");
parentdiv.appendChild(elem1);
}
}
}
}
You are creating an infinite loop.
The nodeList you create with document.getElementsByTagName("a") is live i.e. if you add a link to the page it will appear in this list automatically! Yes, that's right, even without requerying. Here's a reference doc.
You are adding links to the nodeList which are then matched and added to the end on the nodeList which are then matched and so on and so on
To do what you want to do you should create an initial array of links like this.
//creates a real js array from a nodelist
var list = Array.prototype.slice.call( document.getElementsByTagName("a"), 0 );
Here is an explanation of Array.prototype.slice.call
Also change case-sensitive mistake:
var text1 = document.createTextNode(output.innerhtml);
To
var text1 = document.createTextNode(output.innerHTML);
This following script almost does what I need. What I'm trying to do is go through the opened documents, 139 of them, and save them as jpeg. However what it's lacking is moving from one opened document to the other, so it saved the same image over 139 times. I assumed doc.close() would close the opened document and give a new one focus, but it doesn't.
Here's the code:
var destination = "C:/Documents and Settings/Administrator/My Documents/small images"
for(var i = 0; i < 5; i++)
{
doc = documents[i];
name_ = doc.name.substring(0, doc.name.indexOf('.'))
saveForWebPNG(destination, name_);
doc.close();
}
function saveForWebPNG(outputFolderStr, filename)
{
var opts, file;
opts = new ExportOptionsSaveForWeb();
opts.format = SaveDocumentType.JPEG;
opts.quality = 60;
if (filename.length > 27) {
file = new File(outputFolderStr + "/temp.jpg");
activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
file.rename(filename + ".jpg");
}
else {
file = new File(outputFolderStr + "/" + filename + ".jpg");
activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
}
}
According to the Adobe Photoshop CS2 JavaScript Scripting Guide it looks like you need to assign to the Application.activeDocument property to make that document the currently selected one for any actions. This makes sense since you're using that property in the saveForWebPNG function without explicitly activating the document in the iterator in the first block. It might be as simple as the following change:
for (var i = 0; i < 5; i++) {
var doc = documents[i];
app.activeDocument = doc; // Select that document.
var name = doc.name.substring(0, doc.name.indexOf('.'))
saveForWebPNG(destination, name);
doc.close();
}
However, I don't have a copy of Photoshop and haven't verified this solution.
I know this is a lot late, but I just came across this question and feel like I might have a solution that someone down the road may be able to use. So here goes.
One solution is to adjust the for loop. Let's say there are 5 documents open. app.documents.length would be 5. When you close one, the length is now 4, then 3, etc. i is counting up as app.documents.length is decreasing. When i = 3, app.documents.length = 2. I think that iterating backwards would do the trick.
for (i = app.documents.length - 1; i >= 0; i--) { ... }
The answer from #maerics is correct.
However, if you don't know the index of the given document you can reference it by name like in this example:
// Assume 'hello.psd' and 'world.psd' are in same folder at script.
// Open the first file. It is the active document.
var scriptFile = new File($.fileName)
var scriptPath = scriptFile.parent.fsName
var file1obj = File(scriptPath + '/hello.psd')
var file1 = open(file1obj)
// Open the second file. The second file is now the active document.
var file2obj = File(scriptPath + '/world.psd')
var file2 = open(file2obj)
// Make the first file the active document
app.activeDocument = file1
// Make the second file the active document
app.activeDocument = file2
+1 for jbiz's solution. I couldn't figure out why my loop wouldn't complete.
for (i=app.documents.length-1; i >= 0; i--) {
doc = app.documents[i];
app.activeDocument = doc;
...
do whatever you need, save & close
...
}
app.documents.length gets shorter with every iteration though the loop if you close the document when you're done.
You want to close the current selected (or active) document:
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);