Copy link to clipboard
Copied
Hello:
I have folder "A" full of PNG images (200) that are actually clipping masks and folder "B" is a set of photos (200). Both sets are in identical dimensions US letter 8.5 × 11".
Is it possible to make action/script for batch processing that will take photo #1 from folder "A" and photo #1 from folder B"" and clip it, photo #2 from folder "A" and photo #2 from folder "B" and clip it, and so on?
I will always have new set of clipping masks and new set of photos that need to be clipped in specific way.
Is there any way to automate this work?
Thanks in advance.
2 Correct answers
Create on your desktop 2 folders like in your example with appropriate content: A, B
If their resolution is other than 300, then change that for example to 72 in the script.
Change in the code '*.png' chunk (for folder B) to other extension if they're not png.
Run script, wait some time and find resultant files in self created C desktop folder:
function crt() {
aD.activeLayer.name = 'Bottom'; (ref = new ActionReference()).putEnumerated
(sTT('menuItemClass'), sTT('menuItemType'), sTT('screenM
...
Depending on one of described scenarios replace:
while(A.length) parng(shft = A.shift(), 'dLayerRelinkToFile'), parng(B.shift(), 'Event'),
to:
while(A.length) parng(shft = A.shift(), 'dLayerRelinkToFile'), parng(B[0], 'Event'),
or:
while(B.length) parng(A[0], 'dLayerRelinkToFile'), parng(shft = B.shift(), 'Event'),
Explore related tutorials & articles
Copy link to clipboard
Copied
This will need a script, it is beyond an action.
The following scripts can be modifed as needed.
I don't have time now to customise if you can't script, but I will have time in 24 hours or so.
EDIT:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-open-files-and-layer-them/m-p/12532657
https://community.adobe.com/t5/photoshop-ecosystem-discussions/auto-merge-files/m-p/10753387
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
Thank you.
The best answer fro me is to know it is possible, now it is only matter of finding person that knows how to write scripts.
I do not have knowledge to write scripts or modify them so I will copy paste this and share it on FB hopefully someone will respond with the functional script for what I am trying to achieve.
THANK YOU!!
Copy link to clipboard
Copied
I'm sure that somebody here can help, I'll check back tomorrow when I have time. If I have time before then I'll update the code.
Copy link to clipboard
Copied
As promised, here is the final code:
/*
Stack Clipping Mask Image Folder and Image Folder to PNG Output Folder.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/batch-clipping-between-two-folders-one-with-mask-one-with-photos/td-p/12688057
Stephen Marsh, v1.0 - 19th January 2022
Note: It is assumed that the png filenames in the input folders are the same (or will at least sort as expected).
*/
#target photoshop
(function () {
if (app.documents.length === 0) {
try {
// Clipping mask group image input (folder 1)
var folder1 = Folder.selectDialog("Select the clipping group mask image folder:");
if (folder1 === null) {
alert('Script cancelled!');
return;
}
// Image file to clip input (folder 2)
var folder2 = Folder.selectDialog("Select the main image to layer above:");
if (folder2 === null) {
alert('Script cancelled!');
return;
}
// Validate input folder selection
var validateInputDir = (folder1.fsName === folder2.fsName);
if (validateInputDir === true) {
alert("Script cancelled as both the input folders are the same!");
return;
}
// Limit the file input to PNG
var list1 = folder1.getFiles(/\.(png)$/i);
var list2 = folder2.getFiles(/\.(png)$/i);
// Alpha-numeric sort
list1.sort();
list2.sort();
// Validate that folder 1 & 2 lists are not empty
var validateEmptyList = (list1.length > 0 && list2.length > 0);
if (validateEmptyList === false) {
alert("Script cancelled as one of the input folders is empty!");
return;
}
// Validate that the item count in folder 1 & 2 matches
var validateListLength = (list1.length === list2.length);
if (validateListLength === false) {
alert("Script cancelled as the input folders don't have equal quantities of images!");
return;
}
// Output folder
var outputFolder = Folder.selectDialog('Select the output folder:', '');
if (outputFolder == null) {
return
}
// Save and set the dialog display settings
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Perform the stacking and saving
for (var i = 0; i < list1.length; i++) {
var doc = open(list1[i]);
var docName = doc.name;
placeFile(list2[i], 100);
// Select the top layer
doc.activeLayer = app.activeDocument.layers[0];
// Run menu item for Create Clipping Mask
app.runMenuItem(stringIDToTypeID('groupEvent'));
/*
// Create clipping mask from active layer
var idgroupEvent = stringIDToTypeID( "groupEvent" );
var desc316 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref73 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref73.putEnumerated( idlayer, idordinal, idtargetEnum );
desc316.putReference( idnull, ref73 );
executeAction(idgroupEvent, desc316, DialogModes.NO);
// Create clipping mask from active layer
var idgroupEvent = stringIDToTypeID("groupEvent");
executeAction(idgroupEvent, undefined, DialogModes.NO);
*/
// Trim transparency (optional)
// app.activeDocument.trim(TrimType.TRANSPARENT);
// PNG export save for web options
var pngOptions = new ExportOptionsSaveForWeb();
pngOptions.PNG8 = false;
pngOptions.transparency = true;
pngOptions.interlaced = false;
pngOptions.quality = 100;
pngOptions.includeProfile = true;
pngOptions.format = SaveDocumentType.PNG;
// Export PNG
doc.exportDocument(File(outputFolder + "/" + docName), ExportType.SAVEFORWEB, pngOptions)
/*
var pngOptions = new PNGSaveOptions();
pngOptions.compression = 0 //0-9
pngOptions.interlaced = false;
var newFile = new File(decodeURI(outputFolder) + "/" + docName);
*/
/*
// Save as PNG
doc.saveAs(newFile, pngOptions, true, Extension.LOWERCASE);
*/
doc.close(SaveOptions.DONOTSAVECHANGES);
}
function placeFile(file, scale) {
try {
var idPlc = charIDToTypeID("Plc ");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc2.putPath(idnull, new File(file));
var idFTcs = charIDToTypeID("FTcs");
var idQCSt = charIDToTypeID("QCSt");
var idQcsa = charIDToTypeID("Qcsa");
desc2.putEnumerated(idFTcs, idQCSt, idQcsa);
var idOfst = charIDToTypeID("Ofst");
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID("Hrzn");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idHrzn, idPxl, 0.000000);
var idVrtc = charIDToTypeID("Vrtc");
var idPxl = charIDToTypeID("#Pxl");
desc3.putUnitDouble(idVrtc, idPxl, 0.000000);
var idOfst = charIDToTypeID("Ofst");
desc2.putObject(idOfst, idOfst, desc3);
var idWdth = charIDToTypeID("Wdth");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idWdth, idPrc, scale);
var idHght = charIDToTypeID("Hght");
var idPrc = charIDToTypeID("#Prc");
desc2.putUnitDouble(idHght, idPrc, scale);
var idAntA = charIDToTypeID("AntA");
desc2.putBoolean(idAntA, true);
executeAction(idPlc, desc2, DialogModes.NO);
} catch (e) {}
}
// End of script
app.displayDialogs = savedDisplayDialogs;
app.beep();
var listCount = list1.length;
alert('Script completed!' + '\n' + listCount + ' transparent PNG files saved to:' + '\r' + outputFolder.fsName);
} catch (err) {
alert("An unexpected error has occurred!");
}
} else {
alert('Please close all open documents before running this script!');
}
}());
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
Better to post a code referring to problem or link to snippet in other thread.
Copy link to clipboard
Copied
I posted the two scripts that I was suggesting as start points, so there is no problem etc... Except that I didn't have time to provide a full customised script, only the two example scripts.
I'll certainly provide the reworked code as promised when I have time, even though you have provided a solution while I am busy elsewhere.
Copy link to clipboard
Copied
That what I mean, links would suffice before you provide working code 😉
Copy link to clipboard
Copied
I see your point, however, with the recent experience in broken links with the switch to new forum software, repeating the code seems safer for unknown future reference than a link that may break.
Copy link to clipboard
Copied
As to the broken links you may ask of moderation privileges for yourself to edit posts with them. Then you'll replace them by working ones, if earlier find the thread by its name.
Copy link to clipboard
Copied
Those are options, I prefer the option where there is seamless forum transfer with no problems 😉
Copy link to clipboard
Copied
Since rash decisions fail, we must correct faults of others to have 'our' space the way we want.
Copy link to clipboard
Copied
Create on your desktop 2 folders like in your example with appropriate content: A, B
If their resolution is other than 300, then change that for example to 72 in the script.
Change in the code '*.png' chunk (for folder B) to other extension if they're not png.
Run script, wait some time and find resultant files in self created C desktop folder:
function crt() {
aD.activeLayer.name = 'Bottom'; (ref = new ActionReference()).putEnumerated
(sTT('menuItemClass'), sTT('menuItemType'), sTT('screenModeFullScreen'));
(dsc = new ActionDescriptor()).putReference(sTT('null'), ref),
executeAction(sTT('select'), dsc, DialogModes.NO);
(ref = new ActionReference()).putProperty(sTT('property'), gP = sTT('generalPreferences'))
ref.putClass(sTT('application')); (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref);
(dsc2 = new ActionDescriptor()).putBoolean(sTT('placeRasterSmartObject'), false)
dsc1.putObject(sTT('to'), gP, dsc2), executeAction(sTT('set'), dsc1)
executeAction(sTT('newPlacedLayer'))
}
sTT = stringIDToTypeID; Folder(C = (pth = '~/desktop/') + 'C/').create()
A = File(pth + 'A').getFiles('*.png'), B = File(pth + 'B').getFiles('*.png');
(aD = documents.add(UnitValue(2550,'px'), UnitValue(3300, 'px'), 300, '', null,
DocumentFill.TRANSPARENT, null, null, 'none')).suspendHistory('crt', 'crt()')
function loop() {
function parng(v1, v2) {
(dsc = new ActionDescriptor()).putPath(sTT('null'), v1)
executeAction(sTT('place' + v2), dsc)
}
while(A.length) parng(shft = A.shift(), 'dLayerRelinkToFile'), parng(B.shift(), 'Event'),
(ref = new ActionReference()).putEnumerated(sTT('layer'), sTT('ordinal'), sTT('targetEnum')),
(dsc = new ActionDescriptor()).putReference(sTT('null'), ref), executeAction(sTT('groupEvent'), dsc),
aD.saveAs(File(C + shft.name), png, true), aD.activeHistoryState = aD.historyStates[2]
}
png = new PNGSaveOptions
aD.suspendHistory('loop', 'loop()')
aD.close(SaveOptions.DONOTSAVECHANGES)
Copy link to clipboard
Copied
IT WORKED!!!
For people not that familiarized with scripting and what to do when someone gives you block of text as script these are the steps:
Open Notepad and copy paste the text that was given to you as script.
Save the file with unique name and add extension .jsx at the end. It will ask you are you sure, just accept.
Look for C:\Program Files\Adobe\Adobe Photoshop 2021\Presets\Scripts and paste the file you just created there.
Obviously create folders named A and B on your desktop if you want to use this one, and place same size and 300DPI images in those folders. Folder A is for clipping masks files, and B for photos to be clipped.
Open Photoshop and under File menu look for Scripts. You should have your script name listed there. Click on it and let it run.
In my case it generated folder C with my photos clipped by my frames.
PERFECT! Going to test it now on more photos.
Copy link to clipboard
Copied
@Kukurykus Hi, sorry to bother you on Sunday.
The script you created works magnificently. I have a plead. How do I change it to get two additional scripts for specific situations:
a) one script for situation where I have a lot of mask files in folder A but only one image in folder B and I want all different masks to be applied to same image with results in C being different mask applied to identical photo
b) one script for situation where I have a one mask file in folder A but a lot of images in folder B and I want one mask A to be applied to a lot of different images in B with results in C being photos with same mask applied on them
At the moment I am "cheating" by duplicating same mask file in A and run action or same photo in B and run action.
Thank you.
Copy link to clipboard
Copied
Depending on one of described scenarios replace:
while(A.length) parng(shft = A.shift(), 'dLayerRelinkToFile'), parng(B.shift(), 'Event'),
to:
while(A.length) parng(shft = A.shift(), 'dLayerRelinkToFile'), parng(B[0], 'Event'),
or:
while(B.length) parng(A[0], 'dLayerRelinkToFile'), parng(shft = B.shift(), 'Event'),
Copy link to clipboard
Copied
PERFECT! Works exactly as described.
@Kukurykus Not sure do you care for the BG story, but you just helped me to the Moon and back, and I am single mother trying to make some side money with selling graphic templates online from my hand drawing. So far I am making a $1 per week (I know, low, but I am just starting) and this is going to help me soooo much because after the batch action I will decorate each file to be extra unique.
THANK YOU!!!