Illustrator scripting - javascript

I am writing a script for an active doc in Illustrator. The active doc already has the spot swatch for "LEAD" in it. All the paths I have to set and symbols need to be set to this swatch. I have worked my way around it by deleting the swatch then re-adding it to the doc. This works for all my paths and objects created. There are 3 symbols in the active doc that are being placed by scrip, that are already set to the spot swatch. When my script deletes the swatch it resets the symbol to 100% black process. Is there a way to pull the swatch from the active doc?All path items reqiure the leadSpotColor variable to set that color. The LEAD swatch already exist in the active doc. If i do not add the swatch remove line before hand it errors out, but the swatch remove line sets my symbols already in the active doc to 100% process black, and they also need to be set to the LEAD swatch.
if ( app.documents.length = "LEAD" ) {
swatchToDelete = app.activeDocument.swatches["LEAD"];
swatchToDelete.remove();
}
var leadSpot = doc.spots.add();
var leadSpotColor = new CMYKColor();
leadSpotColor.cyan = 0;
leadSpotColor.magenta = 0;
leadSpotColor.yellow = 0;
leadSpotColor.black = 100;
leadSpot.name = "LEAD";
leadSpot.colorType = ColorModel.SPOT;
leadSpot.color = leadSpotColor;
var leadSpotColor = new SpotColor();
leadSpotColor.spot = leadSpot;

Why would you want to delete the swatch if you can just edit it ?
var main = function(){
var doc,
leadClr, c;
if(!app.documents.length) return;
doc = app.activeDocument;
leadClr = getLeadColor(doc);
if ( leadClr===null ) {
var leadSpot = doc.spots.add();
var leadSpotColor = new CMYKColor();
leadSpotColor.cyan = 0;
leadSpotColor.magenta = 0;
leadSpotColor.yellow = 0;
leadSpotColor.black = 100;
leadSpot.name = "LEAD";
leadSpot.colorType = ColorModel.SPOT;
leadSpot.color = leadSpotColor;
var leadSpotColor = new SpotColor();
leadSpotColor.spot = leadSpot;
}
else {
c = leadClr.color.spot.color;
c.cyan = 0;
c.magenta = 0;
c.yellow = 0;
c.black = 100;
}
};
var getLeadColor = function(doc){
var clrs = doc.swatches,
n = clrs.length;
while (n-- ) {
if ( clrs[n].name=="LEAD" ) return clrs[n];
}
return null;
}
main();
I would recommend adding some prevention mechanism like ensure swatch is actually a spot prior to reach teh spot property.

First of all first line of your code is wrong
if ( app.documents.length = "LEAD" )
How you can compare length with string "LEAD", its should be a number and also in if statement we use conditional operator and what you are doing is assigning value in if statement.
Here is the script for LEAD spot, that will give you spot color if exist otherwise it will create new spot color with name "LEAD"
function main() {
var currentDocument;
var leadSpotColor;
if (!app.documents.length) {
alert("No document is open");
return;
}
currentDocument = app.activeDocument;
leadSpotColor = getLeadSpotColor(currentDocument);
applyColorToAllPath(leadSpotColor, currentDocument);
}
function getLeadSpotColor(currentDocument) {
try {
var leadSpotColor = currentDocument.spots.getByName('LEAD')
return leadSpotColor;
} catch (e) {
var color = new CMYKColor();
color.cyan = 0;
color.magenta = 0;
color.yellow = 0;
color.black = 100;
var newSpot = currentDocument.spots.add();
newSpot.name = "LEAD";
newSpot.colorType = ColorModel.SPOT;
newSpot.color = color;
var leadSpotColor = new SpotColor();
leadSpotColor.spot = newSpot;
return leadSpotColor;
}
}
function applyColorToAllPath(leadSpotColor, currentDocument) {
// Change code as per your requiremnt. I just handled for pathItems. You can similary for symbols.
var pathItems = currentDocument.pathItems;
for (var i = 0; i < pathItems.length; i++) {
pathItems[i].filled = true;
pathItems[i].fillColor = leadSpotColor;
pathItems[i].stroke = true;
pathItems[i].strokeColor = leadSpotColor;
}
}
main();

Related

Add a paragraph or table etc. at Cursor

I have a function for adding the contents of a separate google document at the cursor point within the active document, but I haven't been able to get it to work. I keep getting the "Element does not contain the specified child element" exception, and then the contents gets pasted to the bottom of the document rather than at the cursor point!
function AddTable() {
//here you need to get document id from url (Example, 1oWyVMa-8fzQ4leCrn2kIk70GT5O9pqsXsT88ZjYE_z8)
var FileTemplateFileId = "1MFG06knf__tcwHWdybaBk124Ia_Mb0gBE0Gk8e0URAM"; //Browser.inputBox("ID der Serienbriefvorlage (aus Dokumentenlink kopieren):");
var doc = DocumentApp.openById(FileTemplateFileId);
var DocName = doc.getName();
//Create copy of the template document and open it
var docCopy = DocumentApp.getActiveDocument();
var totalParagraphs = doc.getBody().getParagraphs(); // get the total number of paragraphs elements
Logger.log(totalParagraphs);
var cursor = docCopy.getCursor();
var totalElements = doc.getNumChildren();
var elements = [];
for (var j = 0; j < totalElements; ++j) {
var body = docCopy.getBody();
var element = doc.getChild(j).copy();
var type = element.getType();
if (type == DocumentApp.ElementType.PARAGRAPH) {
body.appendParagraph(element);
} else if (type == DocumentApp.ElementType.TABLE) {
body.appendTable(element);
} else if (type == DocumentApp.ElementType.LIST_ITEM) {
body.appendListItem(element);
}
// ...add other conditions (headers, footers...
}
Logger.log(element.editAsText().getText());
elements.push(element); // store paragraphs in an array
Logger.log(element.editAsText().getText());
for (var el = 0; el < elements.length; el++) {
var paragraph = elements[el].copy();
var doc = DocumentApp.getActiveDocument();
var bodys = doc.getBody();
var cursor = doc.getCursor();
var element = cursor.getElement();
var container = element.getParent();
try {
var childIndex = body.getChildIndex(container);
bodys.insertParagraph(childIndex, paragraph);
} catch (e) {
DocumentApp.getUi().alert("There was a problem: " + e.message);
}
}
}
You want to copy the objects (paragraphs, tables and lists) from the document of 1MFG06knf__tcwHWdybaBk124Ia_Mb0gBE0Gk8e0URAM to the active Document.
You want to copy the objects to the cursor position on the active Document.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification points:
In your script, appendParagraph, appendTable and appendListItem are used at the 1st for loop. I think that the reason that the copied objects are put to the last of the document is due to this.
var body = docCopy.getBody(); can be put to the out of the for loop.
In your case, I think that when the 1st for loop is modified, 2nd for loop is not required.
When above points are reflected to your script, it becomes as follows.
Modified script:
function AddTable() {
var FileTemplateFileId = "1MFG06knf__tcwHWdybaBk124Ia_Mb0gBE0Gk8e0URAM";
var doc = DocumentApp.openById(FileTemplateFileId);
var docCopy = DocumentApp.getActiveDocument();
var body = docCopy.getBody();
var cursor = docCopy.getCursor();
var cursorPos = docCopy.getBody().getChildIndex(cursor.getElement());
var totalElements = doc.getNumChildren();
for (var j = 0; j < totalElements; ++j) {
var element = doc.getChild(j).copy();
var type = element.getType();
if (type == DocumentApp.ElementType.PARAGRAPH) {
body.insertParagraph(cursorPos + j, element);
} else if (type == DocumentApp.ElementType.TABLE) {
body.insertTable(cursorPos + j, element);
} else if (type == DocumentApp.ElementType.LIST_ITEM) {
body.insertListItem(cursorPos + j, element);
}
}
}
It seems that DocName is not used in your script.
References:
insertParagraph()
insertTable()
insertListItem()
If I misunderstood your question and this was not the result you want, I apologize. At that time, can you provide the sample source Document? By this, I would like to confirm it.

Looping through layers and setting them to visible

I'm trying to loop through the layers in an InDesign doc and set all of them to visible. This is to ensure that file collection occurs correctly.
I put together the following
var myDocument = app.activeDocument;
//make all layers visable
for (i = 0; i < myDocument.layers.length; i++) {
if(myDocument.layers[i].visible = false) {
myDocument.layers[i].visible = true;
};
};
This is excerpted from a larger script that automates the file collect, this is just the routine for the layers.
For context here's the actual script.
function Left(str, n){
if (n <= 0)
return "";
else if (n > String(str).length)
return str;
else
return String(str).substring(0,n);
}
function Right(str, n){
if (n <= 0)
return "";
else if (n > String(str).length)
return str;
else {
var iLen = String(str).length;
return String(str).substring(iLen, iLen - n);
}
}
if (app.documents.length != 0){
var myDocument = app.activeDocument;
var docName = myDocument.name;
var docName = Left(docName, String(docName).length-5)
//alert(docName);
var myFolder = new Folder ("~/Desktop/"+docName+"/");
//myFolder.create("Bob");s
/*new Folder ("~/Desktop/Collected/Hi-Res PDF/");
new Folder ("~/Desktop/Collected/RELEASE INFO/");*/
//make all layers visable
for (i = 0; i < myDocument.layers.length; i++) {
if(myDocument.layers[i].visible = false) {
myDocument.layers[i].visible = true;
};
};
myDocument.packageForPrint (myFolder,1,1,0,1,0,0,0);
var newFolder = new Folder ("~/Desktop/"+docName+"/RELEASE INFO/");
newFolder.create();
var inddFolder = new Folder ("~/Desktop/"+docName+"/Indesign Files/");
inddFolder.create();
var newFolder = new Folder ("~/Desktop/"+docName+"/IDML Files/");
newFolder.create();
//Export IMDL File
myDocument.exportFile(ExportFormat.INDESIGN_MARKUP, File("~/Desktop/"+docName+"/IDML Files/"+docName+".idml"), false);
//Move INDD File
//var myInddfile = File("~/Desktop/"+docName+"/"+docName+".indd");
//myDocument.changePath(File(inddFolder),false);
//Rip Low Res PDFs
var myPDFExportPreset = app.pdfExportPresets.item("CP3 Low Rez");
app.activeDocument.exportFile(ExportFormat.pdfType,
File("~/Desktop/"+docName+"/RELEASE INFO/"+docName+"_LR.pdf"), false, myPDFExportPreset);
//Now export the document. You'll have to fill in your own file path.
//app.activeDocument.exportFile(ExportFormat.pdfType, File("~/Desktop/"+docName+"_FILM/RELEASE INFO/"+docName+"_LR.pdf"), false);
var newFolder = new Folder ("~/Desktop/"+docName+"/Hi-Res PDF/");
newFolder.create();
//Rip Hi-Res PDF
var myPDFExportPreset = app.pdfExportPresets.item("Kern Hi Rez Print");
app.activeDocument.exportFile(ExportFormat.pdfType,
File("~/Desktop/"+docName+"/Hi-Res PDF/"+docName+"_HiRes.pdf"), false, myPDFExportPreset);
//Now export the document. You'll have to fill in your own file path.
//app.activeDocument.exportFile(ExportFormat.pdfType, File("~/Desktop/"+docName+"_FILM/Hi-Res PDF/"+docName+"_HiRes.pdf"), false);
myFolder.execute();
}
else{
alert("Please open a document and try again.");
}
Hopefully, when the script executes, all the layers will be set to visible then the file collect will occur.
Use triple equals in your if statement for strict equality. For instance:
for (i = 0; i < myDocument.layers.length; i++) {
if(myDocument.layers[i].visible === false) { // <-- Note the `===` instead of `=`
myDocument.layers[i].visible = true;
};
};
Or even better, you can change it to utilize the Logical NOT ! operator
for (i = 0; i < myDocument.layers.length; i++) {
if (!myDocument.layers[i].visible) { // <-- Change to this.
myDocument.layers[i].visible = true;
};
};
Note: Given your example, the conditional if statement is not actually necessary. You could simply do this instead:
for (i = 0; i < myDocument.layers.length; i++) {
myDocument.layers[i].visible = true;
};
Set everything to be visible
If you actually want to make everything visible - including; InDesign document layers and all page items on the sub-layer(s), then you'll need to do something like this example:
var myDocument = app.activeDocument;
// ...
function makeAllVisible() {
for (i = 0, max = myDocument.layers.length; i < max; i++) {
var currentLayer = myDocument.layers[i];
currentLayer.visible = true; // Make the top level layer visible.
// Make all sub layers visible,
// i.e. make all page items on the current layer visible.
var currentLayerPageItems = currentLayer.allPageItems;
for (x = 0, len = currentLayerPageItems.length; x < len; x++) {
currentLayerPageItems[x].visible = true
}
}
}
makeAllVisible(); // Invoke the function.
// ...

Script to merge layers that are copies Photoshop

I am new to scripting on photoshop and it seems not all javascript is the same. What I'm trying to do is I have a list of layers that are as follows:
Cat pic 1.jpg
Cat pic 1.jpg copy
Dog pic 1.jpg
Dog pic 1.jpg copy
....
I want to merge the ones that are copies of each other so "Cat pic 1.jpg" and "Cat pic 1.jpg copy" and create one layer from the two which is just "Cat pic 1.jpg".
They are all active and there is no shapes or anything so its just layers. I have about 300 layers and each one is exactly like that. There is a duplicate of each layer and the name has copy at the end. I wrote a script but I don't know how to merge two layers together. My code doesn't work. It is pieced together from someone trying to sort the layers alphabetically.
Basically I had a layer list and I flipped it horizontally and now I need to merge the left half with the right half. The left is without the word 'copy'.
Any help is greatly appreciated guys! Please feel free to ignore all my code I have zero confidence in it.
Thanks in advance!
#target photoshop
var layers = activeDocument.layers;
var layersArray = [];
var len = layers.length;
// store all layers in an array
for (var i = 0; i < len; i++) {
layersArray.push(layers[i]);
}
var layersOrig= [];
for (var i = 0; i < len; i++) {
var cond = myIndexOf(layersArray[i], "copy");
if (cond === -1) {
layersOrig.push(layersArray[i]);
delete layersArray[i];
}
}
layersOrig.sort();
// sort layer top to bottom
layersArray.sort();
for (var i = 0; i < len; i++) {
layersArray[i] = merge(layersOrig[i], layersArray[i];
}
for (i = 0; i < len; i++) {
layersArray[i].move(layers[i], ElementPlacement.PLACEBEFORE);
}
function myIndexOf(array, x){
var n=-1, N=array.length;
while (++n<N && array[n]!==x);
return n<N ? n : -1;
};
Maybe like this?
function main()
{
var layersInfo = getAllLayersNames(); //getting myself an object of layer names and IDs
for (layerName in layersInfo)
{
deselectLayers(); //deselecting all layers first
if (layersInfo[layerName].length == 1) continue; //if there's only one layer in the object: ignore it
for (var i = 0; i < layersInfo[layerName].length; i++)
{
selectById(layersInfo[layerName][i], true); //selecting layers-clones by IDs
}
mergeDown(); //merge down selected layers
activeDocument.activeLayer.name = layerName; //renaming the resulting layer to original layer name
}
/////////////////////////////////////////////////////////////////////////////////////
// functions
function getAllLayersNames()
{
var lyrs = {};
try
{
activeDocument.backgroundLayer;
var layers = 0
}
catch (e)
{
var layers = 1;
};
while (true)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), layers);
try
{
var desc = executeActionGet(ref);
}
catch (err)
{
break;
}
var lyr = {};
lyr.name = desc.getString(charIDToTypeID("Nm "));
var nameWithoutCopy = lyr.name.replace(/\scopy.*/, '');
lyr.id = desc.getInteger(stringIDToTypeID("layerID"));
if (lyrs[nameWithoutCopy] == undefined) lyrs[nameWithoutCopy] = [lyr.id]
else lyrs[nameWithoutCopy].push(lyr.id);
layers++;
}
return lyrs
};
function selectById(id, add)
{
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putIdentifier(charIDToTypeID('Lyr '), id);
desc1.putReference(charIDToTypeID('null'), ref1);
if (add) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
};
function deselectLayers()
{
var desc60 = new ActionDescriptor();
var ref30 = new ActionReference();
ref30.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc60.putReference(charIDToTypeID('null'), ref30);
executeAction(stringIDToTypeID('selectNoLayers'), desc60, DialogModes.NO);
};
function mergeDown()
{
var desc11 = new ActionDescriptor();
executeAction(charIDToTypeID('Mrg2'), desc11, DialogModes.NO);
};
}
app.activeDocument.suspendHistory("rename all copies", "main()");
Input > Result:

JavaScript cannot find method a second time?

I'm attempting to build a poker game. The method in question is very simple, and it works when it runs the first time.
This part isn't perfect convention because I'm just using it to test my methods:
var $ = function (id) { return document.getElementById(id); };
var test = function() {
var deck = new POKER.Deck();
var hand = new POKER.Hand();
for (var i = 0; i < 7; i++){
hand.addCard(deck.dealCard());
}
hand.sortByRank();
for (var j = 0; j < 7; j++){
var img = document.createElement("img");
var card = hand.getCardAtIndex(j); //** <------- WORKS HERE**
img.src = card.getImage();
$("images").appendChild(img);
}
var testHand = new POKER.Hand();
testHand = hand.removePairs();
for (var k = 0; k < testHand.length; k++) {
var img2 = document.createElement("img");
var card2 = testHand.getCardAtIndex(k); // **<------FAILS HERE**
img2.src = card2.getImage();
$("handImg").appendChild(img2);
}
};
window.onload = function() {
test();
};
The first and second loop work, and the hand is displayed and everything. When it gets to the last loop, the debugger tells me "TypeError: testHand.getCardAtIndex is not a function"
I was attempting to test the removePairs method (to test for straights more easily), and when watching the variables in the debugger, testHand clearly gets populated correctly. The method seems to work just fine.
getCardAtIndex:
POKER.Hand.prototype.getCardAtIndex = function(index) {
return this.cards[index];
};
removePairs:
POKER.Hand.prototype.removePairs = function(){
var allCards = this.cards;
var tempCards = [];
var uniqueRanks = [];
var unique;
for(var i = 0; i < allCards.length; i++){
unique = true;
for(var j = 0; j < uniqueRanks.length; j++){
if(allCards[i].getRank() == uniqueRanks[j]){
unique = false;
break;
}
}
if(unique){
uniqueRanks.push(allCards[i].getRank());
tempCards.push(allCards[i]);
}
}
return tempCards;
};
I'm completely perplexed.
var testHand = new POKER.Hand();
testHand = hand.removePairs();
hand.removePairs() returns an Array, not a Hand object.
That's why you don't have access to the getCardAtIndex method.
If cards is a public property you could do:
testHand.cards = hand.removePairs();
Or you can have a setter method:
testHand.setCards(hand.removePairs);

Photoshop Javascript to get all layers in the active document

I'm sure it should be discussed before by Photoshop scripters. I write a solution as following. I think it's logically right, but the result is not correct. Anybody can help to check where's wrong in the code, or have ideas for this topic? I want to get all the layers in a document.
Code:
function getAllLayersInLayerSets(layerNodes) {
var retList = [];
for (var i=0; i<layerNodes.length; i++) {
if(layerNodes[i].layerSets.length > 0)
{
var tmp = getAllLayersInLayerSets(layerNodes[i].layerSets);
var j = (tmp == null) ? -1 : tmp.length-1;
while(tmp && j>=0)
{
retList.push(tmp[i]);
j--;
}
}
for(var layerIndex=0; layerIndex < layerNodes[i].artLayers.length; layerIndex++)
{
var layer=layerNodes[i].artLayers[layerIndex];
retList.push(layer);
}
}
return retList;
}
Many thanks for any help or discussion.
I know this is an old thread, but this might be useful for someone.
I was looking for a function that would get me all the ArtLayers in a Photoshop comp, including layers nested in groups. The above function was returning undefined, so I modified it and got it to work.
var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);
function collectAllLayers (doc, allLayers){
for (var m = 0; m < doc.layers.length; m++){
var theLayer = doc.layers[m];
if (theLayer.typename === "ArtLayer"){
allLayers.push(theLayer);
}else{
collectAllLayers(theLayer, allLayers);
}
}
return allLayers;
}
Minor expansion on Ghoul Fool's post to only get all VISIBLE art layers in the active document. :P
// Get layers in a document
var sourceDocument = app.activeDocument;
var visibleLayers = [];
var visibleLayers = collectAllLayers(sourceDocument, visibleLayers);
// Print out total layers found
alert(visibleLayers.length);
// Recursively get all visible art layers in a given document
function collectAllLayers (parent, allLayers)
{
for (var m = 0; m < parent.layers.length; m++)
{
var currentLayer = parent.layers[m];
if (currentLayer.typename === "ArtLayer")
{
if(currentLayer.visible)
{
allLayers.push(currentLayer);
}
}
else
{
collectAllLayers(currentLayer, allLayers);
}
}
return allLayers;
}
To get all the layers (and sub layers) you have to have a recursive function
var allLayers = new Array();
var theLayers = collectAllLayers(app.activeDocument, 0);
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
if (theLayer.typename != "ArtLayer")
{
allLayers.push(level + theLayer.name);
collectAllLayers(theLayer, level + 1)
}
}
}
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc29.putReference(charIDToTypeID('null'), ref23);
executeAction(stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO);
}

Categories