Move layers to coordinates from text file - Photoshop scripting - 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 );
}

Related

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

How do I add a radius line from the center of the circle to a point on the circle

The following code adds a circle of given radius to the graphics layer on an ArcGIS map. How can I add a line that joins center of the circle to any point on the circle to the graphics layer.
Basically the question is how do I calculate a point on the circle, draw a line that joins the center to the point on the circle and add it to the graphics layer.
performSearchPoint : function(e) {
var self = this;
var radius = $('#radius-distance').val();
if(radius > 0 && radius < 100000){
$('#besideMouse').removeClass('hide');
$('#besideMouse').show();
var loadingBMint = setInterval(this.loadingBM, 0);
var searchPointClick = OURAPP.App.Map.on("click",function(evt) {
loadingBMint = clearInterval(loadingBMint);
$('#besideMouse').hide();
var radius = $('#radius-distance').val();
var units = $("input:radio[name='unitsGroup']:checked").val();
if (units == "miles"){
units = "9035"; // if we use GeometryService
} else {
units = "9003"; // if we use GeometryService
}
//clear only search graphics
for ( var gr in OURAPP.App.Map.graphics.graphics) {
if(OURAPP.App.Map.graphics.graphics[gr].infoTemplate != null){
var template = OURAPP.App.Map.graphics.graphics[gr].infoTemplate;
if(template != "undefined" || template != null){
if(template.title.trim() == "Search Graphic"){
OURAPP.App.Map.graphics.remove(OURAPP.App.Map.graphics.graphics[gr]);
}
}}}
/*do buffer geometry for draw circle and use the circle geometry to get the features*/
var geoService = new OURAPP.esri.GeometryService("http://XXXX:YYYY/arcgis/rest/services/Utilities/Geometry/GeometryServer");
var params = new OURAPP.esri.BufferParameters();
params.geometries = [ evt.mapPoint ];
params.distances = [ radius ];
params.unit = units;
params.bufferSpatialReference = OURAPP.App.Map.spatialReference;
params.outSpatialReference = new OURAPP.esri.SpatialReference(4326);
var bufferPolygon = new OURAPP.esri.Polygon;
bufferPolygon.spatialReference = new OURAPP.esri.SpatialReference(4326);
geoService.buffer(params,function(geometries) {
var symbol = new OURAPP.esri.SimpleFillSymbol()
.setColor(null).outline.setColor("red");
dojo.forEach(geometries,function(geometry) {
geometry.spatialReference = new OURAPP.esri.SpatialReference(4326);
var graphic = new OURAPP.esri.Graphic(geometry,symbol);
// add name to identify the search graphics
var template = new OURAPP.esri.InfoTemplate(graphic.geometry);
template.setTitle("Search Graphic");
template.setContent("Map Query circle with Radius: " + radius);
graphic.setInfoTemplate(template);
OURAPP.App.Map.graphics.add(graphic);
bufferPolygon = geometry;
OURAPP.App.Map.setExtent(graphic.geometry.getExtent().expand(2));
});
self.searchType="Distance Search from point";
self.nameofplace=radius + " "+$("input:radio[name='unitsGroup']:checked").val();
self.showCount(bufferPolygon);
});
searchPointClick.remove();
});
}
},
I was able to draw a line and add it to the graphics layer using the following. The [-XX.XXXXXXXXXXXX,YY.YYYYYYYYYYY] is a random point on the map, Now only thing left is to find a point on a circle. So now the question becomes how to find a point which is X miles from a known point(Center of the circle) along the same latitude.
var lineSymbol = new OURAPP.esri.CartographicLineSymbol(
OURAPP.esri.CartographicLineSymbol.STYLE_SOLID,
new OURAPP.esri.Color([255,0,0]), 2,
OURAPP.esri.CartographicLineSymbol.CAP_SQUARE,
OURAPP.esri.CartographicLineSymbol.JOIN_MITER, 5
);
var lineGeometry = new OURAPP.esri.Polyline;
lineGeometry.spatialReference = new OURAPP.esri.SpatialReference(4326);
lineGeometry.addPath([[evt.mapPoint.getLongitude(),evt.mapPoint.getLatitude()], [-XX.XXXXXXXXXXXX,YY.YYYYYYYYYYY]])
var lineGraphic = new OURAPP.esri.Graphic(lineGeometry, lineSymbol);
OURAPP.App.Map.graphics.add(lineGraphic);
This is the best possible one i came up with and its working.
var lineSymbol = new OURAPP.esri.CartographicLineSymbol(
OURAPP.esri.CartographicLineSymbol.STYLE_SOLID,
new OURAPP.esri.Color([255,0,0]), 2,
OURAPP.esri.CartographicLineSymbol.CAP_SQUARE,
OURAPP.esri.CartographicLineSymbol.JOIN_MITER, 5
);
var radiusInMeters;
if (selectedUnit == "miles"){
radiusInMeters = radius*1609.34; //have to convert it to meters.
} else {
radiusInMeters = radius*0.3048; //have to convert it to meters.
}
// Calculate the new map point on the circle.
var radians = Math.PI/180;
var ltLong = OURAPP.esri.webMercatorUtils.xyToLngLat(evt.mapPoint.x + radiusInMeters*Math.cos(radians), evt.mapPoint.y + radiusInMeters*Math.sin(radians));
// Calculate the new map point on the circle.
var lineGeometry = new OURAPP.esri.Polyline;
lineGeometry.spatialReference = new OURAPP.esri.SpatialReference(4326);
lineGeometry.addPath([[evt.mapPoint.getLongitude(),evt.mapPoint.getLatitude()], ltLong]);
var lineGraphic = new OURAPP.esri.Graphic(lineGeometry, lineSymbol);

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);
}