ScriptListener code creates new layer above active layer - photoshop

I've used the scriptlistener to create a new layer. The clever thing it does is places it above the active layer (without moving it from the top after creation) However, I'm at a loss to work out which part of the code it is since they all get complied with executeAction:
function create_new_layer(layername)
{
var idMk = charIDToTypeID( "Mk " );
var desc447 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref217 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
ref217.putClass( idLyr );
desc447.putReference( idnull, ref217 );
var idUsng = charIDToTypeID( "Usng" );
var desc448 = new ActionDescriptor();
var idNm = charIDToTypeID( "Nm " );
desc448.putString( idNm, layername );
var idLyr = charIDToTypeID( "Lyr " );
desc447.putObject( idUsng, idLyr, desc448 );
var idLyrI = charIDToTypeID( "LyrI" );
desc447.putInteger( idLyrI, 57 );
executeAction( idMk, desc447, DialogModes.NO );
}

I think AM code represent actual functions in Photoshop, how they work inside, and DOM is some kind of overlay on top of that. Generally DOM code is limited and can't do a lot of things AM can. In this case ArtLayer.add() pushes a layer to activeDocument.layers so it appear on top of the layers stack, while AM command executes New Layer... command. Also generally AM code works much faster than DOM (up to 10-15x), especially with things like selecting layers and working with them.

Related

Move layers to coordinates from text file - Photoshop scripting

I have a base layer - a map of Europe.
a bunch of "country" layers representing each country goes on top of the base layer.
I have a text file with the x/y coordinates of the top left corner of where each the country is to be placed, in relation to the base layer. The coordinates list is in pixel values separated with commas. And some of the values is negative as well.
So what I want to do is move each country layer according to the coordinate list.
Using Javascript I have been able to load the text file, but I am at a loss how to pass the coordinates to each layer and actually move the layers into place.
I cant seem to add a picture here or even a link - just get an error message.
Trying a hyper link: [Link to image][1]
Sergey Kritskiy , Ghoul Fool - Thank you for all your patience and help with this.
This is what I have for "Code" as of now - lots missing..
main();
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
function main(){
//declare listFile variable, prompt to browse for text file
var listFile = File.openDialog("Open list of coordinates","text(*.txt):*.txt;");
//if no file selected, return
if(listFile == null) return;
//read the selected text file (listFile) to a string(listString) - read coordinates from text File
listFile.open('r') ;
var listString = listFile.read();
listFile.close();
//splitting at line breaks, convert into array of strings
fileList = listString.split(' ');
//Need to tell what is X-value and what is Y-value
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
for (var i = numOfLayers -1; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
// Here is where each layer should be paired to its coordinate from the text file - But how to do it?
// move the layer
moveLayer(moveX , moveY);
}
}
//iterate array of strings (coordinates), move layers acording to coordinates in the loaded text document
//for(var i=0; i<=fileList.length; i++){
// var theFile =new File(fileList[i]);
}
};```
[1]: https://www.mediafire.com/view/oms4kv7kt6l6zsf/coordinates_list_and_layers.JPG/file
Basically you want a function to translate a layer (from its original position to its intended position)
You'll also need to work in pixels, which'll make life easier.
You'll either have an object on an array of countries with their respective offsets.
Loop over all the layers. See if the layer name matches a country. It does? Then move that layer.
This'll give you a rough idea, but only works with maps from 1883 where Lichtenstein was the only known country in the world, which naturally made mapping easier.
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
for (var i = numOfLayers -1; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
if (srcDoc.artLayers[i].name == "Lichtenstein")
{
var moveX = 100;
var moveY = 40;
// move the layer
moveLayer(moveX , moveY);
}
}
// Put unit preferences back
app.preferences.rulerUnits = originalUnits;
// FUNCTION moveLayer (dx, dy) translates layer by dx, dy
function moveLayer(dx, dy)
{
// =======================================================
var id9297 = charIDToTypeID( "move" );
var desc2040 = new ActionDescriptor();
var id9298 = charIDToTypeID( "null" );
var ref1412 = new ActionReference();
var id9299 = charIDToTypeID( "Lyr " );
var id9300 = charIDToTypeID( "Ordn" );
var id9301 = charIDToTypeID( "Trgt" );
ref1412.putEnumerated( id9299, id9300, id9301 );
desc2040.putReference( id9298, ref1412 );
var id9302 = charIDToTypeID( "T " );
var desc2041 = new ActionDescriptor();
var id9303 = charIDToTypeID( "Hrzn" );
var id9304 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9303, id9304, dx );
var id9305 = charIDToTypeID( "Vrtc" );
var id9306 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9305, id9306, dy );
var id9307 = charIDToTypeID( "Ofst" );
desc2040.putObject( id9302, id9307, desc2041 );
executeAction( id9297, desc2040, DialogModes.NO );
}
So putting it all together you want something like this:
// Switch off any dialog boxes
displayDialogs = DialogModes.ERROR; // OFF
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
main();
function main()
{
//declare listFile variable, prompt to browse for text file
var listFile = File.openDialog("Open list of coordinates","text(*.txt):*.txt;");
//if no file selected, return
if(listFile == null) return;
//read the selected text file (listFile) to a string(listString) - read coordinates from text File
listFile.open('r') ;
var listString = listFile.read();
listFile.close();
//splitting at line breaks, convert into array of strings
fileList = listString.split("\n");
//Need to tell what is X-value and what is Y-value
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
var c = 0;
// ignore the background? Start at numOfLayers -2
for (var i = numOfLayers -2; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
var theLayerName = srcDoc.artLayers[i].name;
var line = fileList[c].split(",");
var moveX = line[0];
var moveY = line[1];
// alert(theLayerName + " : " + moveX + ", " + moveY);
// Here is where each layer should be paired to its coordinate from the text file - But how to do it?
// move the layer
moveLayer(moveX , moveY);
// increment the file list counter
c+=1;
}
}
// set ruler units back to how it was
app.preferences.rulerUnits = originalUnits;
// Set Display Dialogs back to normal
displayDialogs = DialogModes.ALL; // NORMAL
// FUNCTION moveLayer (dx, dy) translates layer by dx, dy
function moveLayer(dx, dy)
{
// =======================================================
var id9297 = charIDToTypeID( "move" );
var desc2040 = new ActionDescriptor();
var id9298 = charIDToTypeID( "null" );
var ref1412 = new ActionReference();
var id9299 = charIDToTypeID( "Lyr " );
var id9300 = charIDToTypeID( "Ordn" );
var id9301 = charIDToTypeID( "Trgt" );
ref1412.putEnumerated( id9299, id9300, id9301 );
desc2040.putReference( id9298, ref1412 );
var id9302 = charIDToTypeID( "T " );
var desc2041 = new ActionDescriptor();
var id9303 = charIDToTypeID( "Hrzn" );
var id9304 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9303, id9304, dx );
var id9305 = charIDToTypeID( "Vrtc" );
var id9306 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9305, id9306, dy );
var id9307 = charIDToTypeID( "Ofst" );
desc2040.putObject( id9302, id9307, desc2041 );
executeAction( id9297, desc2040, DialogModes.NO );
}

Photoshop action to make 1 random layer visible within each group

I'm trying to use Photoshop actions to generate randomized images that are composed of a random sampling of layers. I have 3 groups of layers which are ALL not visible by default.
Within each group I'd like to make 1 random layer visible (in total there will be 3 "on" layers)
Export the whole thing as a .png file.
Repeat n times
Example Groups/Layers:
[FRUITS]
* [Apples]
* [Oranges]
* [Pears]
* [Bananas]
* [Kiwis]
[VEGGIES]
* [Asparagus]
* [Cilantro]
* [Eggplant]
[MEATS]
* [Beef]
* [Pork]
All layers are hidden by default, but when I play an action, I might get the following result (visible layers):
Image1: [Apples] [Eggplant] [Pork]
Image2: [Pears] [Asparagus] [Pork]
Image3: [Kiwis] [Cilantro] [Beef]
Here Is my script, but don't forget to do the following steps before running it:
Hide All Layers and Groups Except Background.
Save Your PSD.
Close and then reopen.
Now you are ready to rock.
Features
Make Unlimited Patterns you want from your groups.
Saved All Patterns As Indexed separate PNG in Separate Folder named PNG.
Watch GIF (below) to understand more:
function Visible() {
var Grps = app.activeDocument.layerSets; // loops through all groups
for(var i = 0; i < Grps.length; i++){
var tmp = app.activeDocument.layerSets[i].layers.length;
app.activeDocument.layerSets[i].visible=true;
var groupChildArr = app.activeDocument.layerSets[i].layers;
var randLays = Math.floor(Math.random() * tmp);
groupChildArr[randLays].visible = true;
Save();
}
Revert();
}
function Save() {
var outFolder = app.activeDocument; // psd name
var outPath = outFolder.path;
var fName = "PNG"; // define folder name
var f = new Folder(outPath + "/" + fName);
if ( ! f.exists ) {
f.create()
}
var saveFile = new File(outPath + "/" + fName +"/" + "Pattern_" + num + ".png");
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.interlaced = false;
app.activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
// Original code - revert function does not work
// for some users
//function Revert(){
// var idslct = charIDToTypeID( "slct" );
// var desc300 = new ActionDescriptor();
// var idnull = charIDToTypeID( "null" );
// var ref163 = new ActionReference();
// var idSnpS = charIDToTypeID( "SnpS" );
// ref163.putName( idSnpS, "test.psd" );
// desc300.putReference( idnull, ref163 );
// executeAction( idslct, desc300, DialogModes.NO );
//}
function Revert(){
var idRvrt = charIDToTypeID( "Rvrt" );
executeAction( idRvrt, undefined, DialogModes.NO );
}
var count = prompt("How many patterns you want","");
for (var x=0 ; x<count;x++){
var num = x+1;
Visible();
}

Photoshop Script for Smart Objects out of fixed folder

sorry for my not so good English, I hope you guys will understand what my problem is.. I donĀ“t know really much about coding.
I have got the following code which allows to choose files that have to be changed in a smartobject in a psd document. I would like to have the code choose from a fixed folder like
../Desktop/Alldesigns
without asking which files I want to proceed.
I hope someone can help me...
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName= myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// jpg options;
var jpgopts = new JPEGSaveOptions();
jpgopts.embedProfile = true;
jpgopts.formatOptions = FormatOptions.STANDARDBASELINE;
jpgopts.matte = MatteType.NONE;
jpgopts.quality = 9;
// check if layer is smart object;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {alert ("selected layer is not a smart object")}
else {
// select files;
if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.psd;*.tif;*.jpg", true)}
else {var theFiles = File.openDialog ("please select files", getFiles, true)};
if (theFiles) {
// work through the array;
for (var m = 0; m < theFiles.length; m++) {
// replace smart object;
theLayer = replaceContents (theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
//save jpg;
myDocument.saveAs((new File(thePath+"/"+theNewName+"-"+theName+".jpg")),jpgopts,true);
}
}
}
};
////// get psds, tifs and jpgs from files //////
function getFiles (theFile) {
if (theFile.name.match(/\.(psd|tif)$/i) != null || theFile.constructor.name == "Folder") {
return true
};
};
////// replace contents //////
function replaceContents (newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc3.putPath( idnull, new File( newFile ) );
var idPgNm = charIDToTypeID( "PgNm" );
desc3.putInteger( idPgNm, 1 );
executeAction( idplacedLayerReplaceContents, desc3, DialogModes.NO );
return app.activeDocument.activeLayer
};
Best wishes from Germany
olee

Randomly deleting parts of image/pixels

I'm wondering whether anyone knows how I might randomly delete/remove certain parts of an image. Is there some sort of filter for this where I can specify the % of the picture that I want to be deleted? (I'm coming up short with my Google searches.)
You could right something like this:
It's not very efficient! As it's looping over a selection and then deleting those pixels. Over and over again.
I tried it with an 1 MB image and a setting of 50 % deletion it took a couple of minutes. So you're warned.
// call the source document
var srcDoc = app.activeDocument;
// Get original width and height
var imageWidth = srcDoc.width.value;
var imageHeight = srcDoc.height.value;
// Selection size for deleting pixels
// You could make these random
var sizeX = 20;
var sizeY = 20;
// Define the number of parts you want to delete
// Area of image = imageWidth * imageHeight
// Example image 1600 x 1200, area = 1920000 pixels
// To delete 50% would be the same as selecting
// an area that's (sizeX * sizeY) *2400 times
var pcent = 0.1; //10% of image
var area = imageWidth * imageHeight;
var selArea = sizeX * sizeY; //selection area
var numParts = pcent * (area/ selArea);
numParts = parseInt(numParts);
for (var i = 0; i < numParts; i++)
{
var randX = Math.floor(Math.random() * (imageWidth-sizeX));
var randY = Math.floor(Math.random() * (imageHeight-sizeY));
// deselect EVERYTHING first
srcDoc.selection.deselect();
// select random position of selection
selectRectangle(randY, randX, randY+sizeY, randX+sizeX);
// Delete those pixels
srcDoc.selection.clear();
// deselect EVERYTHING first
srcDoc.selection.deselect();
}
// function SELECT RECTANGLE(top, left, bottom, right)
//
// Note: co-ordinates are same as script listener
// and not so human-friendly as t,l,r,b.
// --------------------------------------------------------
function selectRectangle(top, left, bottom, right)
{
// =======================================================
var id1 = charIDToTypeID( "setd" );
var desc1 = new ActionDescriptor();
var id2 = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var id3 = charIDToTypeID( "Chnl" );
var id4 = charIDToTypeID( "fsel" );
ref1.putProperty( id3, id4 );
desc1.putReference( id2, ref1 );
var id5 = charIDToTypeID( "T " );
var desc2 = new ActionDescriptor();
var id6 = charIDToTypeID( "Top " );
var id7 = charIDToTypeID( "#Pxl" );
desc2.putUnitDouble( id6, id7, top );
var id8 = charIDToTypeID( "Left" );
var id9 = charIDToTypeID( "#Pxl" );
desc2.putUnitDouble( id8, id9, left );
var id10 = charIDToTypeID( "Btom" );
var id11 = charIDToTypeID( "#Pxl" );
desc2.putUnitDouble( id10, id11, bottom );
var id12 = charIDToTypeID( "Rght" );
var id13 = charIDToTypeID( "#Pxl" );
desc2.putUnitDouble( id12, id13, right );
var id16 = charIDToTypeID( "Rctn" );
desc1.putObject( id5, id16, desc2 );
executeAction( id1, desc1, DialogModes.NO );
}

Photoshop script hide and save with level name

I have a Photoshop file with around 200 levels, I need to save for web every single level with the level's name hiding the other levels...Is there any way to do that with script?
Thanks
This will save out each layer as a jpeg, named after the layer name. You don't need to hide the layers as you go; instead each layer it gets duplicated as a new image, flattened, saved and then closed. Won't work with any groups (normally you have to pay extra for that ;) )
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
var jpegQuality = 12;
for (var i = numOfLayers -1; i >= 0 ; i--)
{
var theLayerName = srcDoc.layers[i].name;
var theFile = srcDoc.path;
srcDoc.activeLayer = srcDoc.artLayers[i];
var id2784 = charIDToTypeID( "Mk " );
var desc707 = new ActionDescriptor();
var id2785 = charIDToTypeID( "null" );
var ref508 = new ActionReference();
var id2786 = charIDToTypeID( "Dcmn" );
ref508.putClass( id2786 );
desc707.putReference( id2785, ref508 );
var id2787 = charIDToTypeID( "Nm " );
desc707.putString( id2787, theLayerName );
var id2788 = charIDToTypeID( "Usng" );
var ref509 = new ActionReference();
var id2789 = charIDToTypeID( "Lyr " );
var id2790 = charIDToTypeID( "Ordn" );
var id2791 = charIDToTypeID( "Trgt" );
ref509.putEnumerated( id2789, id2790, id2791 );
desc707.putReference( id2788, ref509 );
executeAction( id2784, desc707, DialogModes.NO );
app.activeDocument.flatten();
SaveForWeb(theFile, jpegQuality);
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
app.activeDocument = srcDoc;
}
function SaveForWeb(saveFile, jquality)
{
var sfwOptions = new ExportOptionsSaveForWeb();
sfwOptions.format = SaveDocumentType.JPEG;
sfwOptions.includeProfile = false;
sfwOptions.interlaced = 0;
sfwOptions.optimized = true;
sfwOptions.quality = jquality;
activeDocument.exportDocument(saveFile, ExportType.SAVEFORWEB, sfwOptions);
}