Copy link to clipboard
Copied
I have a PS file that has about 30 photos all arranged in little columns and rows. Each photo has text associated with it, a name and a date. Every photo and every bit of text is on it's own layer. Is there a way for Photoshop to take all these layers and just scramble them up/randomly distribute them?
I've seen stuff about Random Fill, but I don't think that's what I want. And I've seen stuff about creating your own paintbrush, but I don't think that's what I want either. I want whatever the Photoshop equivalent is of nicely lining up a bunch of stuff on the bottom of a box, putting the lid on, and then shaking it. Is that even possible?
Copy link to clipboard
Copied
Can you post screenshot with some examples?
If I can understand what you want to do then only script can help you. I will tag few scripters @c.pfaffenbichler @Stephen Marsh @r-bin @jazz-y
Copy link to clipboard
Copied
Yes! I'm sorry, here is a screenshot. I'm still fairly new to Photoshop so I'm not sure if this is sufficient, so please let me know if you need me to screenshot anything else!
Copy link to clipboard
Copied
Oops, I posted too soon.
But what I basically want is all those photos and text layers to just get randomly scattered an image. Imagine that each layer, whether it's a text or image layer, were all printed out on individual pieces of paper, and I just took them all threw them on the ground. They'd just be randomly and messily distributed across an area. That's what I want my final image to look like.
Copy link to clipboard
Copied
For a start, you can try these:
https://www.reddit.com/r/photoshop/comments/5kajgh/how_to_shuffle_layers/
Info on saving and using scripts:
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
Would you consider building this project in InDesign or must it be in Photoshop?
Copy link to clipboard
Copied
Honestly, I'm not sure. I've never used InDesign, and I'm still fairly new to Photoshop! If you have some very beginner friendly tutorials on how I could do this, I'd be happy to give it a shot!
Copy link to clipboard
Copied
Could you please post screenshots with the pertinent Panels (Toolbar, Layers, Options Bar, …) visible?
If the Layers with name and date should stick with the Layer with the image how can they unequivocally be collated?
Copy link to clipboard
Copied
Sure! I'm still pretty new to Photoshop, so I don't know if this is what you need, so please let me know if you need screen shots of anything else!
And I'm not sure what you mean, but I don't want the names and dates to stick with their images. Imagine if every single layer, whether it's an image or text, were printed out on individual pieces of paper, and I just threw them on the ground. That's what I want. I just want all the layers to be scattered randomly across the image I want to create.
Copy link to clipboard
Copied
This is good candidate for data driven graphics. If you can not get job done with some script take a look at variables and data sets which can be formated to place "random" images or images at different layer positions with corresponding captions.
Copy link to clipboard
Copied
This might cause problems with Adjustment Layers, but in your example there don’t seem to be any.
// randomly place layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var myDocument = activeDocument;
var theLayers = collectLayersBounds ();
var docWidth = myDocument.width;
var docHeight = myDocument.height;
var docCenter = [docWidth/2, docHeight/2];
for (var m = 0; m < theLayers.length; m++) {
var thisOne = theLayers[m];
var theId = duplicateMoveRotateScale (false, theLayers[m][1], Math.random()*(docWidth-thisOne[3])-thisOne[5][0]+thisOne[3]/2, Math.random()*(docHeight-thisOne[4])-thisOne[5][1]+thisOne[4]/2, 100, 100, Math.random()*360)
theLayers[m][1] = theId;
};
app.preferences.rulerUnits = originalRulerUnits;
};
////// collect layers //////
function collectLayersBounds () {
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theseBounds = [theBounds.getUnitDoubleValue(stringIDToTypeID("left")), theBounds.getUnitDoubleValue(stringIDToTypeID("top")), theBounds.getUnitDoubleValue(stringIDToTypeID("right")), theBounds.getUnitDoubleValue(stringIDToTypeID("bottom"))];
var theWidth = theseBounds[2] - theseBounds[0];
var theHeight = theseBounds[3] - theseBounds[1];
var theCenter = [theseBounds[0]+theWidth/2, theseBounds[1]+theHeight/2];
theLayers.push([theName, theID, theseBounds, theWidth, theHeight, theCenter])
};
}
catch (e) {};
};
return theLayers
};
////// duplicate layer and move, rotate and scale it //////
function duplicateMoveRotateScale (copyOrNot, theID, theX, theY, theScaleX, theScaleY, theRotation) {
selectLayerByID(theID,false);
smartify (activeDocument.activeLayer);
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID ("property"), charIDToTypeID ("LyrI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
d = executeActionGet(ref);
var theID = d.getInteger(charIDToTypeID('LyrI'));
try{
var idTrnf = charIDToTypeID( "Trnf" );
var desc10 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref6 = new ActionReference();
ref6.putIdentifier( charIDToTypeID( "Lyr " ), theID );
/* ref6.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );*/
desc10.putReference( idnull, ref6 );
var idFTcs = charIDToTypeID( "FTcs" );
var idQCSt = charIDToTypeID( "QCSt" );
var idQcsa = charIDToTypeID( "Qcsa" );
desc10.putEnumerated( idFTcs, idQCSt, idQcsa );
var idOfst = charIDToTypeID( "Ofst" );
var desc11 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc11.putUnitDouble( idHrzn, idPxl, theX );
var idVrtc = charIDToTypeID( "Vrtc" );
var idPxl = charIDToTypeID( "#Pxl" );
desc11.putUnitDouble( idVrtc, idPxl, theY );
var idOfst = charIDToTypeID( "Ofst" );
desc10.putObject( idOfst, idOfst, desc11 );
var idWdth = charIDToTypeID( "Wdth" );
var idPrc = charIDToTypeID( "#Prc" );
desc10.putUnitDouble( idWdth, idPrc, theScaleX );
var idHght = charIDToTypeID( "Hght" );
var idPrc = charIDToTypeID( "#Prc" );
desc10.putUnitDouble( idHght, idPrc, theScaleY );
var idAngl = charIDToTypeID( "Angl" );
var idAng = charIDToTypeID( "#Ang" );
desc10.putUnitDouble( idAngl, idAng, theRotation );
var idIntr = charIDToTypeID( "Intr" );
var idIntp = charIDToTypeID( "Intp" );
var idbicubicAutomatic = stringIDToTypeID( "bicubicAutomatic" );
desc10.putEnumerated( idIntr, idIntp, idbicubicAutomatic );
var idCpy = charIDToTypeID( "Cpy " );
desc10.putBoolean( idCpy, copyOrNot );
executeAction( idTrnf, desc10, DialogModes.NO );
//var thisCopy = app.activeDocument.activeLayer;
return theID
} catch (e) {}
};
////// function to smartify if not //////
function smartify (theLayer) {
// make layers smart objects if they are not already;
if (theLayer.kind != LayerKind.SMARTOBJECT) {
activeDocument.activeLayer = theLayer;
var id557 = charIDToTypeID( "slct" );
var desc108 = new ActionDescriptor();
var id558 = charIDToTypeID( "null" );
var ref77 = new ActionReference();
var id559 = charIDToTypeID( "Mn " );
var id560 = charIDToTypeID( "MnIt" );
var id561 = stringIDToTypeID( "newPlacedLayer" );
ref77.putEnumerated( id559, id560, id561 );
desc108.putReference( id558, ref77 );
executeAction( id557, desc108, DialogModes.NO );
return activeDocument.activeLayer
};
return theLayer
};
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message);
}
};
Copy link to clipboard
Copied
This script is exactly what I have been searching for!
The code is a bit beyone my understanding, however I copied it all and it worked.
I tried to look into the code to limit the amount of rotation allowed, if I was building a collage of photos, I would not want them to be roatated any further than say +/- 20 degrees for example.
How would you go about making this adjustment?
Copy link to clipboard
Copied
Try changing:
Math.random()*360
To:
Math.random()*40-20
Example in context:
var theId = duplicateMoveRotateScale (false, theLayers[m][1], Math.random()*(docWidth-thisOne[3])-thisOne[5][0]+thisOne[3]/2, Math.random()*(docHeight-thisOne[4])-thisOne[5][1]+thisOne[4]/2, 100, 100, Math.random()*40-20)
Copy link to clipboard
Copied
Bingo, that definitely did the trick!
Any chance on getting the scaling part to also specify either the width or height to scale the images to as well?
Currently i am manually scaling each image to 3 inches, either tall or wide depending on orientation, before I run this script and it is rather tedious and seems a bit redundant if this script could already handle the resizing at the same time too.
Copy link to clipboard
Copied
What is the target size in px?
what I are the px dimensions of the source images and their resolution PPI value?
Copy link to clipboard
Copied
Well my working document is 300 dpi so the target size for each picture would work out to be 900px.
Source images px and dpi are all over the place, however when you "place" them into a document of a higher or low resolution than they are, they will adjust their size accordingly to match the destination resolution.
Do you think that the 2 "100"'s, just before where we made the change for rotation, are referring to 100% for the width and height?
Any way to make it specify pixels instead?
Probably going to run into an issue with landscape vs portrait images though.
Copy link to clipboard
Copied
Those are percent and as collectLayersBounds alrady collects the Layers’ widths one can calulate the scale factor.
Copy link to clipboard
Copied
I removed the rotation for testing, but you know how insert it yourself.
// randomly place layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var myDocument = activeDocument;
var theLayers = collectLayersBounds ();
var docWidth = myDocument.width;
var docHeight = myDocument.height;
var docCenter = [docWidth/2, docHeight/2];
for (var m = 0; m < theLayers.length; m++) {
var thisOne = theLayers[m];
//////
var targetSize = 900;
if (thisOne[3] > thisOne[4]) {var theScale = targetSize / thisOne[3] * 100}
else {var theScale = targetSize / thisOne[4] * 100};
//////
var theId = duplicateMoveRotateScale (false, theLayers[m][1], Math.random()*(docWidth-thisOne[3])-thisOne[5][0]+thisOne[3]/2, Math.random()*(docHeight-thisOne[4])-thisOne[5][1]+thisOne[4]/2, theScale, theScale, 0)
theLayers[m][1] = theId;
};
app.preferences.rulerUnits = originalRulerUnits;
};
////// collect layers //////
function collectLayersBounds () {
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theseBounds = [theBounds.getUnitDoubleValue(stringIDToTypeID("left")), theBounds.getUnitDoubleValue(stringIDToTypeID("top")), theBounds.getUnitDoubleValue(stringIDToTypeID("right")), theBounds.getUnitDoubleValue(stringIDToTypeID("bottom"))];
var theWidth = theseBounds[2] - theseBounds[0];
var theHeight = theseBounds[3] - theseBounds[1];
var theCenter = [theseBounds[0]+theWidth/2, theseBounds[1]+theHeight/2];
theLayers.push([theName, theID, theseBounds, theWidth, theHeight, theCenter])
};
}
catch (e) {};
};
return theLayers
};
////// duplicate layer and move, rotate and scale it //////
function duplicateMoveRotateScale (copyOrNot, theID, theX, theY, theScaleX, theScaleY, theRotation) {
selectLayerByID(theID,false);
smartify (activeDocument.activeLayer);
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID ("property"), charIDToTypeID ("LyrI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
d = executeActionGet(ref);
var theID = d.getInteger(charIDToTypeID('LyrI'));
try{
var idTrnf = charIDToTypeID( "Trnf" );
var desc10 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref6 = new ActionReference();
ref6.putIdentifier( charIDToTypeID( "Lyr " ), theID );
/* ref6.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );*/
desc10.putReference( idnull, ref6 );
var idFTcs = charIDToTypeID( "FTcs" );
var idQCSt = charIDToTypeID( "QCSt" );
var idQcsa = charIDToTypeID( "Qcsa" );
desc10.putEnumerated( idFTcs, idQCSt, idQcsa );
var idOfst = charIDToTypeID( "Ofst" );
var desc11 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc11.putUnitDouble( idHrzn, idPxl, theX );
var idVrtc = charIDToTypeID( "Vrtc" );
var idPxl = charIDToTypeID( "#Pxl" );
desc11.putUnitDouble( idVrtc, idPxl, theY );
var idOfst = charIDToTypeID( "Ofst" );
desc10.putObject( idOfst, idOfst, desc11 );
var idWdth = charIDToTypeID( "Wdth" );
var idPrc = charIDToTypeID( "#Prc" );
desc10.putUnitDouble( idWdth, idPrc, theScaleX );
var idHght = charIDToTypeID( "Hght" );
var idPrc = charIDToTypeID( "#Prc" );
desc10.putUnitDouble( idHght, idPrc, theScaleY );
var idAngl = charIDToTypeID( "Angl" );
var idAng = charIDToTypeID( "#Ang" );
desc10.putUnitDouble( idAngl, idAng, theRotation );
var idIntr = charIDToTypeID( "Intr" );
var idIntp = charIDToTypeID( "Intp" );
var idbicubicAutomatic = stringIDToTypeID( "bicubicAutomatic" );
desc10.putEnumerated( idIntr, idIntp, idbicubicAutomatic );
var idCpy = charIDToTypeID( "Cpy " );
desc10.putBoolean( idCpy, copyOrNot );
executeAction( idTrnf, desc10, DialogModes.NO );
//var thisCopy = app.activeDocument.activeLayer;
return theID
} catch (e) {}
};
////// function to smartify if not //////
function smartify (theLayer) {
// make layers smart objects if they are not already;
if (theLayer.kind != LayerKind.SMARTOBJECT) {
activeDocument.activeLayer = theLayer;
var id557 = charIDToTypeID( "slct" );
var desc108 = new ActionDescriptor();
var id558 = charIDToTypeID( "null" );
var ref77 = new ActionReference();
var id559 = charIDToTypeID( "Mn " );
var id560 = charIDToTypeID( "MnIt" );
var id561 = stringIDToTypeID( "newPlacedLayer" );
ref77.putEnumerated( id559, id560, id561 );
desc108.putReference( id558, ref77 );
executeAction( id557, desc108, DialogModes.NO );
return activeDocument.activeLayer
};
return theLayer
};
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message);
}
};
Copy link to clipboard
Copied
I copied the new script entirely and added the rotation part back in.
The scaling part incorpaorated perfectly!
The only issue meow is that a large majority of the photos are shuffled towards the center vertically.
Any thoughts?
The previous script that did not include the scaling part scattered them all over.
Attach image is of about 140 photos.
Copy link to clipboard
Copied
I have not changed the location-coordinates so I suspect this is random.
In my experience people do not necessarily mean »random« when they say »random« … a random distribution is not always an aesthetically pleasing one and one might have to limit the randomness and provide some additional distribution-guidelines.
Crudely one could for example distribute about a fourth of the elements in each of the four quadrants.
Copy link to clipboard
Copied
If it should be necessary to avoid rotated Layers to extend beyond the Canvas’ edges it would be possible to split the rotation and the moving into two operations, so that the Bounding Box resulting from the rotation is known before moving.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now