
Stephen Marsh
Community Expert
Stephen Marsh
Community Expert
Activity
25m ago
Apart from using Adobe Bridge or another browser to eyeball the results, it's possible to script this to various degrees. The following script will check selected files for a strip of black pixels and write the suspect file names and paths to a text file on the desktop. For processing speed, it will make a temporary crop of the canvas width to 3px wide before checking the histogram, which may not always be perfect and could possibly lead to some false-positives being reported.
/*
Log Files With Black Full Width Line to Text File Fast.jsx
Stephen Marsh
v1.0 - 7th March 2025
https://community.adobe.com/t5/photoshop-ecosystem-discussions/black-horizontal-line-across-the-image-after-save-to-tif/m-p/15195817
Note: It is assumed that the documents are RGB mode
*/
#target photoshop
// Open dialog to select files
var theFiles = File.openDialog("Select files to check for full width 0r0g0b pixels", true);
if (theFiles) {
processFiles(theFiles);
} else {
alert("No files selected.");
}
// Function to check histogram for 0r0g0b
function checkHistogramForBlack(doc) {
var histo = doc.histogram;
return histo[0] > 0;
}
// Function to process files
function processFiles(theFiles) {
var resultFile = new File(Folder.desktop + "/BlackPixelsCheckResults.txt");
resultFile.open("w");
resultFile.writeln("Files possibly containing full width 0r0g0b pixels:\n");
// Counter for files with 0r0g0b pixels
var blackFilesCount = 0;
// Loop through files
for (var i = 0; i < theFiles.length; i++) {
var theFile = theFiles[i];
var doc = app.open(theFile);
// Resize canvas to 3px wide, yes it's a hack but it works much faster than looping through all pixels...
// Some edge cases could be falsely logged, but it's probably good enough for most cases!
doc.resizeCanvas(UnitValue(3, "px"), doc.height, AnchorPosition.MIDDLECENTER);
if (checkHistogramForBlack(doc)) {
resultFile.writeln(theFile.fsName);
blackFilesCount++; // Increment counter when 0r0g0b pixels are found
}
doc.close(SaveOptions.DONOTSAVECHANGES);
}
// End of script notification
resultFile.close();
alert("Processing complete!\n" + "Total files checked: " + theFiles.length + "\n" +
"Files with possible full width black pixels: " + blackFilesCount + "\n" +
"Results saved to: " + resultFile.fsName);
resultFile.execute();
}
Copy the code text to the clipboard
Open a new blank file in a plain-text editor (not in a word processor)
Paste the code in
Save as a plain text format file – .txt
Rename the saved file extension from .txt to .jsx
Install or browse to the .jsx file to run (see below)
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
... View more
4 hours ago
does anyone know what charIDToTypeID( "LwCs" ) and charIDToTypeID( "DocI" ) refere to in terms of actions or gui?
By @gerardoc50494125
If TypeID codes are the same as StringID codes, then:
charIDToTypeID( "LwCs" ) = 'lowerCase'
charIDToTypeID( "DocI” ) = 'documentID'
... View more
4 hours ago
So to copy files back and forth is not really a workable option over time.
By @morten_2325
If you're happy to double check and re-render as necessary, which doesn't sound like a great option over time.
... View more
4 hours ago
Right. Easier said than done depending on workload and internal storage. Adobe also says "Adobe is not stating that there should be regular problems storing files and working with external hard disks. " Seems like Adobe is trying to have its cake and eat it to. It's almost like saying try Rawtherapee or DXO.
By @Kovich24
I would presume that other software would have the same issue. If not, you have your answer:
1) save locally and move to removable storage
2) save directly to removable storage and be prepared to double check and re-render when necessary
3) use other software if that proves to be problem free or less problematic
... View more
9 hours ago
@Deborah342639444s96
Scripts can be installed in the application directory - Presets/Scripts. Browsing for a script is just an alternative option. Once installed, a custom keyboard shortcut can be added to the installed script, or an action recording of the script execution can also use an F-key keyboard shortcut.
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html?m=1
If you're working on projects and switching between various open files in each session, then you might find the following script useful:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/scripts-to-save-amp-restore-photoshop-sessions/m-p/14239969#U14946306
... View more
11 hours ago
Try Saving to the internal drive and then copy it to the external drive.
https://helpx.adobe.com/au/photoshop/kb/networks-removable-media-photoshop.html
... View more
Mar 05, 2025
I'm still getting an "object is not safe to edit" error.
By @anthony38519375m1bj
Please share the code and sample files.
... View more
Mar 05, 2025
1 Upvote
I believe that you are trying to mix oil and water.
Untested, but perhaps the UXP can run an Action, with the action calling the ExtendScript code.
... View more
Mar 05, 2025
03:11 PM
To all experiencing this issue, are you saving direct to your computer's local drive, or are you saving over the network or to cabled external media?
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 05, 2025
01:58 PM
1 Upvote
Mar 05, 2025
01:58 PM
1 Upvote
Depending on image content and pixel dimensions, the resampling/interpolation algorithm can make a visual difference, so that is why it's there.
A checkbox to disable would be appreciated by some users.
You can use a script that I created to resize without a preview:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/image-preview-in-resize-dialog/m-p/15192988#M856339
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 05, 2025
05:51 AM
1 Upvote
Mar 05, 2025
05:51 AM
1 Upvote
@suzy_95
I created the following script to stack alpha-numeric sorting images from two separate folders to a two-layer file. This should get you 90% of the way there. Before the script saves the file to various file formats, an action run by the script can complete any further automation that you require (the action can run another script if more complex processing is required that can't be achieved via an action).
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-open-files-and-layer-them/m-p/12532657#U14933502
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 05, 2025
12:39 AM
1 Upvote
Mar 05, 2025
12:39 AM
1 Upvote
Another option is to just have standard layers with the 3 hats in an upper layer group, then have the base image in a lower group and use this script:
https://github.com/mechanicious/photoshopCompositionComposer
... View more
Mar 04, 2025
01:06 PM
I tried to create a script with ChatGPT, but it didn't work. This one does. Thank you so much.
By @marief2223714
Thank you, you're welcome.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 04, 2025
01:38 AM
1 Upvote
Mar 04, 2025
01:38 AM
1 Upvote
I have been working on a generic GUI version of the Data Sets to JPEG script, allowing users to select from JPEG, PNG, WEBP, TIFF and PSB output file formats. Although I could have added PSD, this is covered by the native Data Set export functionality.
/*
Photoshop Variables Data Sets to Files GUI v1-0.jsx
v1.0 - 4rd March 2025, Initial Release
Updated and extended by Stephen Marsh, tested with v2019, v2020, v2021, v2024 and v2025 on Mac and Windows.
Original script by Mike Hale, 2010
NOTE: The active document must have Data Sets already defined.
https://community.adobe.com/t5/photoshop-ecosystem-discussions/using-datasets/td-p/2665594
https://forums.adobe.com/thread/628182
https://forums.adobe.com/message/2773935#2773935
*/
#target photoshop
// Adjust the following "user friendly" variables as required. A GUI for these file format options isn't planned!
// Filename suffix separator
var separator = '_'; // '_' | ' ' | '-' (underscore, space or hyphen)
// saveJPEG global variables
var jpegEmbedColorProfile = true; // Boolean: true | false
var jpegFormatOptions = FormatOptions.STANDARDBASELINE; // FormatOptions.STANDARDBASELINE | FormatOptions.OPTIMIZEDBASELINE | FormatOptions.PROGRESSIVE
var jpegMatte = MatteType.NONE; // MatteType.NONE | MatteType.WHITE | MatteType.BLACK
var jpegQuality = 10; // Numeric: 0 - 12 (low quality to highest quality)
// savePNG global variables
var pngCompression = 1; // Numeric: 0 - 9 (low compression to highest)
var pngInterlaced = false; // Boolean: true | false
// saveWebP global variables
var webPCompressionType = "compressionLossy"; // String: "compressionLossless" | "compressionLossy"
var webPCompIsLossless = false; // Boolean: true | false
var webPQuality = 75; // Numeric: 0 - 100 (low quality to highest quality)
var webPIncludeXMPData = true; // Boolean: true | false
var webPIncludeEXIFData = false; // Boolean: true | false
var webPIncludePsExtras = false; // Boolean: true | false
var webPLowerCase = true; // Boolean: true | false
var webPEmbedProfiles = true; // Boolean: true | false
// saveTIFF global variables
var tiffEmbedColorProfile = true; // Boolean: true | false
var tiffByteOrder = ByteOrder.IBM; // ByteOrder.MACOS | ByteOrder.IBM
var tiffTransparency = true; // Boolean: true | false
var tiffLayerCompression = LayerCompression.ZIP; // LayerCompression.RLE | LayerCompression.ZIP
var tiffInterleaveChannels = true; // Boolean: true | false
var tiffAlphaChannels = true; // Boolean: true | false
var tiffAnnotations = true; // Boolean: true | false
var tiffSpotColors = true; // Boolean: true | false
var tiffSaveLayers = true; // Boolean: true | false
var tiffSaveImagePyramid = false; // Boolean: true | false
var tiffImageCompression = TIFFEncoding.TIFFLZW; // TIFFEncoding.NONE | TIFFEncoding.JPEG | TIFFEncoding.TIFFLZW | TIFFEncoding.TIFFZIP
///// GUI FUNCTION /////
try {
var createDialog = function () {
// Confirm with the user that the file meets the criteria
if (!confirm("Data Sets must be created before running this script. Continue?", false)) {
return;
}
// Create the dialog window
var dlg = new Window('dialog', 'Data Sets to Files (v1.0)');
dlg.preferredSize = [500, 350];
// Create main panel to hold input controls
dlg.mainPanel = dlg.add('panel', undefined, '');
dlg.mainPanel.alignment = ['fill', 'fill'];
dlg.mainPanel.margins = [15, 15, 15, 15];
dlg.mainPanel.spacing = 10;
dlg.mainPanel.alignChildren = 'left';
// CSV File button and path
var csvGroup = dlg.mainPanel.add('group');
csvGroup.orientation = 'column';
csvGroup.alignChildren = 'fill';
csvGroup.alignment = ['fill', 'top'];
csvGroup.add('statictext', undefined, 'Select the Data Set .csv file to import:');
var csvBtnGroup = csvGroup.add('group');
csvBtnGroup.alignment = ['fill', 'top'];
csvBtnGroup.alignChildren = 'left';
dlg.mainPanel.csvFileBtn = csvBtnGroup.add('button', undefined, 'Browse...', { name: 'browse' });
dlg.mainPanel.csvFileBtn.preferredSize.width = 100;
// Add a panel for the CSV file path
var csvPathPanel = csvGroup.add('panel');
csvPathPanel.alignment = ['fill', 'top'];
csvPathPanel.margins = 10;
dlg.mainPanel.csvFilePath = csvPathPanel.add('statictext', undefined, 'No file selected', { truncate: "middle" });
dlg.mainPanel.csvFilePath.alignment = ['fill', 'top'];
dlg.mainPanel.csvFilePath.minimumSize.width = 350;
// Output Folder button and path
var outputGroup = dlg.mainPanel.add('group');
outputGroup.orientation = 'column';
outputGroup.alignChildren = 'fill';
outputGroup.alignment = ['fill', 'top'];
outputGroup.add('statictext', undefined, 'Select the output folder:');
var outputBtnGroup = outputGroup.add('group');
outputBtnGroup.alignment = ['fill', 'top'];
outputBtnGroup.alignChildren = 'left';
dlg.mainPanel.outputFolderBtn = outputBtnGroup.add('button', undefined, 'Browse...', { name: 'browse' });
dlg.mainPanel.outputFolderBtn.preferredSize.width = 100;
// Add a panel for the output folder path
var outputPathPanel = outputGroup.add('panel');
outputPathPanel.alignment = ['fill', 'top'];
outputPathPanel.margins = 10;
dlg.mainPanel.outputFolderPath = outputPathPanel.add('statictext', undefined, 'No folder selected', { truncate: "middle" });
dlg.mainPanel.outputFolderPath.alignment = ['fill', 'top'];
dlg.mainPanel.outputFolderPath.minimumSize.width = 350;
// File Format Group
var formatGroup = dlg.mainPanel.add('group');
formatGroup.orientation = 'column';
formatGroup.alignChildren = 'left';
formatGroup.alignment = ['left', 'top'];
// Add a static text label
formatGroup.add('statictext', undefined, 'Select the output file format:');
// Add a group for the dropdown and description
var formatDropdownGroup = formatGroup.add('group');
formatDropdownGroup.orientation = 'row';
formatDropdownGroup.alignChildren = 'left';
// Create the conditional dropdown options array based on Photoshop version 2022 check/test
var formatOptions = ["JPEG", "PNG", "TIFF", "PSB"];
if (parseFloat(app.version) >= 23) {
formatOptions.splice(2, 0, "WEBP"); // Insert into the array at index 2 (3rd position)
}
// Add a dropdown list for format selection using the conditional format options
dlg.mainPanel.formatList = formatDropdownGroup.add('dropdownlist', undefined, formatOptions);
// Default selection to the first entry (JPEG)
dlg.mainPanel.formatList.selection = 0;
// Set the preferred width for the dropdown list
dlg.mainPanel.formatList.preferredSize.width = 70;
// Add a static text label that updates with format selection
dlg.mainPanel.formatDescription = formatDropdownGroup.add('statictext', undefined, '(' + jpegFormatOptions.toString().replace(/FormatOptions\./, '') + ' Format Option, Quality ' + jpegQuality + ')');
// Add a static text label for filename suffix options
formatGroup.add('statictext', undefined, 'Select the filename suffix:');
// Add a dropdown list for filename suffix options
dlg.mainPanel.suffixList = formatGroup.add('dropdownlist', undefined, ['First Column in CSV', 'Dataset Index No.']);
// Default selection to 'First column in CSV'
dlg.mainPanel.suffixList.selection = 0;
// Set the preferred width for the suffix dropdown list
dlg.mainPanel.suffixList.preferredSize.width = 160;
// Create button group for Cancel and OK buttons
var buttonGroup = dlg.add('group');
buttonGroup.orientation = 'row';
buttonGroup.alignment = 'right';
buttonGroup.spacing = 5;
dlg.cancelBtn = buttonGroup.add('button', undefined, 'Cancel', { name: 'cancel' });
dlg.okBtn = buttonGroup.add('button', undefined, 'OK', { name: 'ok' });
// Update the static text when the dropdown selection changes
dlg.mainPanel.formatList.onChange = function () {
var selectedFormat = dlg.mainPanel.formatList.selection.text;
var descriptions = {
'JPEG': '(' + jpegFormatOptions.toString().replace(/FormatOptions\./, '') + ' Format Option, Quality ' + jpegQuality + ')',
'PNG': '(Lossless Compression ' + pngCompression + ', Supports Transparency)',
'WEBP': '(Lossy Compression ' + webPQuality + ', Supports Transparency)',
'TIFF': '(' + tiffByteOrder.toString().replace(/ByteOrder\./, '') + ' Byte Order, ' + tiffImageCompression.toString().replace(/TIFFEncoding\./, '') + ' Compression)',
'PSB': '(Large Document Format)'
};
dlg.mainPanel.formatDescription.text = descriptions[selectedFormat];
};
// Return the dialog
return dlg;
};
} catch (error) {
alert(error + ', Line: ' + error.line);
}
///// HELPER FUNCTIONS /////
function fileImportDataSets(file) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putClass(stringIDToTypeID("dataSetClass"));
desc.putReference(charIDToTypeID("null"), ref);
desc.putPath(charIDToTypeID("Usng"), new File(file));
desc.putEnumerated(charIDToTypeID("Encd"), stringIDToTypeID("dataSetEncoding"), stringIDToTypeID("dataSetEncodingAuto"));
desc.putBoolean(stringIDToTypeID("eraseAll"), true);
desc.putBoolean(stringIDToTypeID("useFirstColumn"), true);
executeAction(stringIDToTypeID("importDataSets"), desc, DialogModes.NO);
};
function applyDataSet(setName) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var reference = new ActionReference();
reference.putName(s2t("dataSetClass"), setName);
descriptor.putReference(s2t("null"), reference);
executeAction(s2t("apply"), descriptor, DialogModes.NO);
};
function getDataSetNames(csvFileRef) {
var _ftn = function (string) {
var csvItems = string.split(",");
var datasetName = csvItems[0].replace(/(^['\"]|['\"]$)/g, ''); // Clean both single and double quote-escaped values
return datasetName;
};
csvFileRef.open();
var datasetArray = [];
var i = 0;
var csvString;
while (!csvFileRef.eof) {
csvString = csvFileRef.readln();
// Skip empty lines
if (csvString.length < 2) continue;
datasetArray[i] = _ftn(csvString);
i++;
}
csvFileRef.close();
return datasetArray;
};
function paddedSetNo(number) {
var str = number.toString();
// 4-digit padding (e.g., 1 = 0001, 23 = 0023)
while (str.length < 4) {
str = "0" + str;
}
return str;
}
function jpegSaveOptions() {
var jpgOptions = new JPEGSaveOptions();
jpgOptions.formatOptions = jpegFormatOptions;
jpgOptions.embedColorProfile = jpegEmbedColorProfile;
jpgOptions.matte = jpegMatte;
jpgOptions.quality = jpegQuality;
return jpgOptions;
};
function pngSaveOptions() {
var pngOptions = new PNGSaveOptions();
pngOptions.compression = pngCompression;
pngOptions.interlaced = pngInterlaced;
return pngOptions;
};
function saveWebP(saveFile) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), s2t(webPCompressionType));
if (webPCompIsLossless == false) {
descriptor2.putInteger(s2t("quality"), webPQuality);
}
// Metadata options
descriptor2.putBoolean(s2t("includeXMPData"), webPIncludeXMPData);
descriptor2.putBoolean(s2t("includeEXIFData"), webPIncludeEXIFData);
descriptor2.putBoolean(s2t("includePsExtras"), webPIncludePsExtras);
// WebP format and save path
descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
descriptor.putPath(s2t("in"), saveFile);
// The extension
descriptor.putBoolean(s2t("lowerCase"), webPLowerCase);
// Embed color profile
descriptor.putBoolean(s2t("embedProfiles"), webPEmbedProfiles);
// Execute the save
executeAction(s2t("save"), descriptor, DialogModes.NO);
}
function saveTIFF(saveFile) {
var tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = tiffEmbedColorProfile;
tiffSaveOptions.byteOrder = tiffByteOrder;
tiffSaveOptions.transparency = tiffTransparency;
tiffSaveOptions.layers = tiffSaveLayers;
tiffSaveOptions.layerCompression = tiffLayerCompression;
tiffSaveOptions.interleaveChannels = tiffInterleaveChannels;
tiffSaveOptions.alphaChannels = tiffAlphaChannels;
tiffSaveOptions.annotations = tiffAnnotations;
tiffSaveOptions.spotColors = tiffSpotColors;
tiffSaveOptions.saveImagePyramid = tiffSaveImagePyramid;
tiffSaveOptions.imageCompression = tiffImageCompression;
// Execute the save
app.activeDocument.saveAs(saveFile, tiffSaveOptions, true, Extension.LOWERCASE);
}
function savePSB(saveFile) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
descriptor2.putBoolean(s2t("maximizeCompatibility"), true);
descriptor.putObject(s2t("as"), s2t("largeDocumentFormat"), descriptor2);
descriptor.putPath(s2t("in"), saveFile);
descriptor.putBoolean(s2t("lowerCase"), true);
descriptor.putBoolean(s2t("layers"), true);
// Execute the save
executeAction(s2t("save"), descriptor, DialogModes.NO);
}
///// MAIN SCRIPT EXECUTION /////
try {
if (app.documents.length > 0) {
var dlg = createDialog();
// CSV selection button
dlg.mainPanel.csvFileBtn.onClick = function () {
var csvFileRef = File.openDialog("Select CSV file:");
if (csvFileRef !== null) {
dlg.mainPanel.csvFilePath.text = csvFileRef.fsName;
}
};
// Output folder selection button
dlg.mainPanel.outputFolderBtn.onClick = function () {
var saveFolder = Folder.selectDialog("Select the output folder to save the files to:");
if (saveFolder !== null) {
dlg.mainPanel.outputFolderPath.text = saveFolder.fsName;
}
};
// Generate the dialog
if (dlg.show() === 1) {
// File and folder variables
var csvFileRef = new File(dlg.mainPanel.csvFilePath.text);
var saveFolder = new Folder(dlg.mainPanel.outputFolderPath.text);
var selectedFormat = dlg.mainPanel.formatList.selection.text;
var selectedSuffixOption = dlg.mainPanel.suffixList.selection.index;
// Import the data sets from the CSV file
fileImportDataSets(csvFileRef);
// Variables for the loop
var datasetNames = getDataSetNames(csvFileRef);
var fileCounter = 0;
var originalDocName = app.activeDocument.name.replace(/\.[^\.]+$/, ''); // Capture the base name once
// Loop through the dataset names and save each file
for (var i = 1; i < datasetNames.length; i++) {
applyDataSet(datasetNames[i]);
// Define suffix based on selection
var suffix = '';
// First column in CSV
if (selectedSuffixOption === 0) {
suffix = getDataSetNames(csvFileRef)[i].replace(/.*\//, '').replace(/\.[^\.]+$/, '');
// 4-digit padded set number
} else if (selectedSuffixOption === 1) {
suffix = paddedSetNo(i);
}
// Construct the filename
var fileName = originalDocName + separator + suffix;
var extension = '';
if (selectedFormat === 'JPEG') {
extension = '.jpg';
} else if (selectedFormat === 'PNG') {
extension = '.png';
} else if (selectedFormat === 'WEBP') {
extension = '.webp';
} else if (selectedFormat === 'TIFF') {
extension = '.tif';
} else if (selectedFormat === 'PSB') {
extension = '.psb';
}
// Save folder and file name
var saveFile = new File(saveFolder + "/" + fileName + extension);
// Save the file with the selected format
if (selectedFormat === 'JPEG') {
app.activeDocument.saveAs(saveFile, jpegSaveOptions(), true, Extension.LOWERCASE);
} else if (selectedFormat === 'PNG') {
app.activeDocument.saveAs(saveFile, pngSaveOptions(), true, Extension.LOWERCASE);
} else if (selectedFormat === 'WEBP') {
saveWebP(saveFile);
} else if (selectedFormat === 'TIFF') {
saveTIFF(saveFile);
} else if (selectedFormat === 'PSB') {
savePSB(saveFile);
}
// Increment the file counter
fileCounter++;
}
// End of script
app.beep();
alert(fileCounter + " " + selectedFormat + " files have been saved to:" + "\n" + saveFolder.fsName);
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
} else {
alert('A template file must be open before running this script...');
}
} catch (error) {
alert(error + ', Line: ' + error.line);
}
Copy the code text to the clipboard
Open a new blank file in a plain-text editor (not in a word processor)
Paste the code in
Save as a plain text format file – .txt
Rename the saved file extension from .txt to .jsx
Install or browse to the .jsx file to run (see below):
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 04, 2025
12:33 AM
1 Upvote
Mar 04, 2025
12:33 AM
1 Upvote
The text file encoding may not be correct for images using non-standard characters.
Can you upload the .csv file? You might need to rename it .txt for the forum software.
... View more
Mar 04, 2025
12:29 AM
Actions have always worked this way, you would need a script to store and retrieve a folder path for saving.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 04, 2025
12:15 AM
2 Upvotes
Mar 04, 2025
12:15 AM
2 Upvotes
@Bojan Živković - As far as I know, actions record the specific mask details for that individual image, so scripting this has the same limitations.
Actions are the "old school" way of batch processing inside Photoshop. The Camera Raw filter isn't always going to play nicely with Actions or scripts.
@Mike35315067k4t9 - Do this outside of Photoshop, directly in the Adobe Camera Raw plugin on RGB JPEG/TIFF files, where a preset using AI masks works correctly when batch processing the applied settings from one image to all selected images in the filmstrip. If one has Lightroom then that's another option.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 03, 2025
06:10 PM
1 Upvote
Mar 03, 2025
06:10 PM
1 Upvote
Actions have always recorded an absolute path from the recording system, and optionally a filename as well:
If running the action in interactive "modal" mode on a single open image, you can change the filename and location.
If running the action via the automate > batch command, then there's a checkbox to "override action save options" so that the recorded path and or name aren't used (otherwise the batch would overwrite itself).
... View more
Mar 02, 2025
04:10 PM
You're welcome.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 02, 2025
02:49 PM
1 Upvote
Mar 02, 2025
02:49 PM
1 Upvote
I have been extending the original code from the late Mike Hale here:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/using-datasets/td-p/2665594/page/2
I am currently using a confirm dialog for the user to OK to run the script, which relies on them knowing that the file already has Variables/Data Sets defined.
Ideally, the script would check for the existence of Data Sets and terminate if none were found.
Unfortunately, the action manager code is beyond me, so I was wondering if anyone knew how to check for this.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 02, 2025
01:21 PM
2 Upvotes
Mar 02, 2025
01:21 PM
2 Upvotes
@powerful_Zephyr5EF9 – Have you downloaded and installed the ScriptingListener plugin?
https://helpx.adobe.com/au/photoshop/kb/downloadable-plugins-and-content.html
This is necessary for things the basic Photoshop ExtendScript DOM does not cover.
Doing so would give you something like this:
var idcolorRange = stringIDToTypeID( "colorRange" );
var desc376 = new ActionDescriptor();
var idfuzziness = stringIDToTypeID( "fuzziness" );
desc376.putInteger( idfuzziness, 10 );
var idcolors = stringIDToTypeID( "colors" );
var idcolors = stringIDToTypeID( "colors" );
var idskinTone = stringIDToTypeID( "skinTone" );
desc376.putEnumerated( idcolors, idcolors, idskinTone );
var idcolorModel = stringIDToTypeID( "colorModel" );
desc376.putInteger( idcolorModel, 0 );
executeAction( idcolorRange, desc376, DialogModes.NO );
var idcopyToLayer = stringIDToTypeID( "copyToLayer" );
executeAction( idcopyToLayer, undefined, DialogModes.NO );
... View more
Mar 01, 2025
07:59 PM
@richardg52861327
Your post has already been moved, no need to repost.
https://community.adobe.com/t5/photoshop-ecosystem/ct-p/ct-photoshop
... View more
Mar 01, 2025
07:38 PM
Is it possible to randomise parameters that aren't integers? For example, the Neon Glow filter that has a parameter that takes a color. Is this something that could be randomised as well
Yes, the Red/Green/Blue values are just three separate integers between 0-255 in value, so easy enough with the code previously provided as a guide.
Another example is the Rough Pastels filter which has a parameter titled scaling that takes in a percent value ranging from 50% to 200%. Could this type of parameter be randomised?
By @ugonnaa21431338
The scaling value is still an integer, so easy enough with the code previously provided as an example.
What will be more challenging are parameters using specific names, such as the texture and the light direction parameters.
Here's an example of randomising the texture, which is based on an array of four names, rather than integers:
var textures = ["texTypeBrick", "texTypeBurlap", "texTypeCanvas", "texTypeSandstone"];
var randomTexture = textures[Math.floor(Math.random() * textures.length)];
alert(randomTexture);
GEfc_roughPastels(6, 4, randomTexture, 111, 20, false);
function GEfc_roughPastels(strokeLength, strokeDetail, theTexture, scaling, relief, invertTexture) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putEnumerated(c2t("GEfk"), c2t("GEft"), s2t("roughPastels"));
descriptor.putInteger(s2t("strokeLength"), strokeLength);
descriptor.putInteger(s2t("strokeDetail"), strokeDetail);
descriptor.putEnumerated(s2t("textureType"), s2t("textureType"), s2t(theTexture));
descriptor.putInteger(s2t("scaling"), scaling);
descriptor.putInteger(s2t("relief"), relief);
descriptor.putEnumerated(s2t("lightDirection"), s2t("lightDirection"), s2t("lightDirBottomRight"));
descriptor.putBoolean(s2t("invertTexture"), invertTexture);
executeAction(c2t("GEfc"), descriptor, DialogModes.NO);
}
You can remove or //comment out the alert line, it's just there so that you can see what is going on.
A similar approach could be used for the light direction, which has eight parameters.
This project will be a labour of love... Good luck!
... View more
Mar 01, 2025
07:22 PM
Using your example of Poster Edges, here is the raw ScriptListener recording:
var idGEfc = charIDToTypeID( "GEfc" );
var desc272 = new ActionDescriptor();
var idGEfk = charIDToTypeID( "GEfk" );
var idGEft = charIDToTypeID( "GEft" );
var idposterEdges = stringIDToTypeID( "posterEdges" );
desc272.putEnumerated( idGEfk, idGEft, idposterEdges );
var idedgeThickness = stringIDToTypeID( "edgeThickness" );
desc272.putInteger( idedgeThickness, 3 );
var idedgeIntensity = stringIDToTypeID( "edgeIntensity" );
desc272.putInteger( idedgeIntensity, 2 );
var idposterization = stringIDToTypeID( "posterization" );
desc272.putInteger( idposterization, 1 );
executeAction( idGEfc, desc272, DialogModes.NO );
Here is how the raw recording looks using the CleanSL script:
GEfc(3, 2, 1);
function GEfc(edgeThickness, edgeIntensity, posterization) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putEnumerated(c2t("GEfk"), c2t("GEft"), s2t("posterEdges"));
descriptor.putInteger(s2t("edgeThickness"), edgeThickness);
descriptor.putInteger(s2t("edgeIntensity"), edgeIntensity);
descriptor.putInteger(s2t("posterization"), posterization);
executeAction(c2t("GEfc"), descriptor, DialogModes.NO);
}
Here I have manually created a function and function call and manually replaced the hard-coded values with variable names for the parameters. This is without using the CleanSL script:
galleryEffects_PosterEdges(3, 2, 1);
function galleryEffects_PosterEdges(thicknessValue, intensityValue, posterizationValue) {
var idGEfc = charIDToTypeID("GEfc");
var desc272 = new ActionDescriptor();
var idGEfk = charIDToTypeID("GEfk");
var idGEft = charIDToTypeID("GEft");
var idposterEdges = stringIDToTypeID("posterEdges");
desc272.putEnumerated(idGEfk, idGEft, idposterEdges);
var idedgeThickness = stringIDToTypeID("edgeThickness");
desc272.putInteger(idedgeThickness, thicknessValue); // Replace the integer with a variable
var idedgeIntensity = stringIDToTypeID("edgeIntensity");
desc272.putInteger(idedgeIntensity, intensityValue); // Replace the integer with a variable
var idposterization = stringIDToTypeID("posterization");
desc272.putInteger(idposterization, posterizationValue); // Replace the integer with a variable
executeAction(idGEfc, desc272, DialogModes.NO);
}
Next, you would then need to work out what the valid range of values are for each parameter from the user interface... Finally, you would then add in the variables to create the random values for each parameter and replace the numerical values with the variable names as I previously did with my initial example.
... View more
Mar 01, 2025
06:01 PM
It's rarely that easy, the names are not always logical or obvious. To self serve, you're going to need to install the following:
ScriptingListener plugin from Adobe:
https://helpx.adobe.com/au/photoshop/kb/downloadable-plugins-and-content.html
Although not strictly necessary, I highly recommend the CleanSL script to refactor and create functions from the basic code recordings:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/clean-sl/td-p/9358420
https://github.com/rendertom/Clean-SL
... View more
Mar 01, 2025
05:40 PM
You need a separate function for each separate filter. Each function would have random parameters that may or may not be shared with other filters.
All of the functions could be in the one script, with function calls as necessary to run specific randomised filters. Or they could all be separate self contained scripts, each with a unique function and function call.
It depends on the parameters as to how one would code the randomised values. Some would be easier than others.
Just how many different filters are you looking at randomising? It could take anywhere from a couple of minutes to much longer, per filter to create the randomised parameters, not including testing and bug fixes.
This can easily be a black hole for time.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 01, 2025
04:20 PM
1 Upvote
Mar 01, 2025
04:20 PM
1 Upvote
Here is a visual example of the how the Photocopy filter would be scripted, using fixed parameters. These fixed parameters would need to be replaced with variables from random generators.
And here is an example of how this would be scripted:
var photocopyRandomDetail = Math.floor(Math.random() * 24) + 1; // Random integer between 1-24
var photocopyRandomDarken = Math.floor(Math.random() * 50) + 1; // Random integer between 1-50
GEfc_photocopy(photocopyRandomDetail, photocopyRandomDarken);
function GEfc_photocopy(detail, darken) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putEnumerated(c2t("GEfk"), c2t("GEft"), s2t("photocopy"));
descriptor.putInteger(s2t("detail"), detail);
descriptor.putInteger(s2t("darken"), darken);
executeAction(c2t("GEfc"), descriptor, DialogModes.NO);
}
Note: I purposely chose a simple example. Some of the filters use parameters which are not simple integers.
... View more
Mar 01, 2025
03:58 PM
Please provide before and after examples.
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 01, 2025
03:51 PM
1 Upvote
Mar 01, 2025
03:51 PM
1 Upvote
@ugonnaa21431338
The easy and short answer is yes.
The harder and longer answer is that it depends. Your question is too generic, it comes down to specifics.
The Filter Gallery has six main groups.
Within each group there are a variable number of separate filters.
Each filter has different parameters, that vary in count and applicable values.
Finally, multiple filters and their parameters can be combined in a single pass by using the + sign to combine their results based on the order of operations
Bottom line is that you need to be very specific... For example:
* How many total filters do you wish to randomise?
* If there were 3 filters in total, should the selection of one of the 3 filters be randomised?
* Once the script runs a specific filter, is it every parameter that needs to be randomised for each filter, or are there only specific parameters within a given filter that require randomisation?
... View more
Community Expert
in Photoshop ecosystem Discussions
Mar 01, 2025
02:59 PM
1 Upvote
Mar 01, 2025
02:59 PM
1 Upvote
I'm not sure if I'm understanding, however, there is the Image > Duplicate command.
... View more