Here is the script I made, you should give it a shot. Just stick this in notepad and save as a .JSX file to run it in photoshop. Sharing as plain text for transparency.
#target photoshop
// Polyfills for compatibility with older JavaScript engines.
if (!Object.keys) {
Object.keys = function(obj) {
var keys = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
keys.push(i);
}
}
return keys;
};
}
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/) {
if (this == null) {
throw new TypeError('Array.prototype.reduce called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var o = Object(this);
var len = o.length >>> 0;
var k = 0;
var value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k < len && !(k in o)) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = o[k++];
}
for (; k < len; k++) {
if (k in o) {
value = callback(value, o[k], k, o);
}
}
return value;
};
}
// Function to retrieve a list of files from a specified folder or from an array of selected files.
function getFilesFromSource(folder, selectedFiles) {
if (selectedFiles) {
// Return the array of selected files if provided.
return selectedFiles;
} else if (folder) {
// If a folder is provided, return an array of files with supported image formats.
return folder.getFiles(function(file) {
return file instanceof File && /\.(jpg|jpeg|png|psd|tiff|tif)$/i.test(file.name);
});
} else {
// If neither a folder nor selected files are provided, throw an error.
throw new Error('No source folder or files selected.');
}
}
var scriptSettings = {
outputFolder: { preset: null, saved: null },
resampleMethod: { preset: 'None', saved: 'None' },
preserveInputFormat: { preset: false, saved: false },
outputFormat: { preset: 'JPG', saved: 'JPG' },
jpegQuality: { preset: 12, saved: null },
deleteSourceFiles: { preset: false, saved: false },
analysisAreaSize: { preset: 10, saved: 10 },
numberOfSampleAreas: { preset: 20, saved: 20 },
outlierThresholds: { preset: { low: 35, high: 65 }, saved: { low: 35, high: 65 } }
};
// Function to get a setting value, falling back to the preset if no saved value is set.
function getSetting(key) {
if (scriptSettings.hasOwnProperty(key)) {
// Return the saved value if it exists, otherwise return the preset value.
return scriptSettings[key].saved !== null ? scriptSettings[key].saved : scriptSettings[key].preset;
} else {
// If the key does not exist, log an error message and return undefined.
$.writeln('Error: Setting key "' + key + '" does not exist.');
return undefined;
}
}
// Function to save a setting value.
function saveSetting(key, value) {
if (scriptSettings.hasOwnProperty(key)) {
// Save the value to the scriptSettings object.
scriptSettings[key].saved = value;
} else {
// If the key does not exist, throw an error.
throw new Error('Setting key "' + key + '" does not exist.');
}
}
// Function to revert settings to their preset values.
function revertToDefaultSettings() {
for (var key in scriptSettings) {
if (scriptSettings.hasOwnProperty(key)) {
// Reset each setting to its preset value.
scriptSettings[key].saved = null;
}
}
}
// Function to display the settings dialog
function showSettingsDialog() {
var settingsDialog = createSettingsDialog(); // Create the settings dialog.
settingsDialog.show(); // Display the settings dialog.
}
// Function to create the main dialog with UI elements for user interaction.
function createDialog() {
var dialog = new Window('dialog', 'Downscale to Actual Size by @WestonCarlisle');
// Header group for the settings button.
var headerGroup = dialog.add('group');
headerGroup.alignment = 'left'; // Align the settings button to the left.
headerGroup.orientation = 'row';
headerGroup.alignChildren = 'center';
// Settings button to open the settings dialog.
var settingsButton = headerGroup.add('button', undefined, 'Settings');
settingsButton.helpTip = "Open settings"; // Tooltip text for the settings button.
settingsButton.onClick = function() {
showSettingsDialog(); // Call the function to display the settings dialog.
};
// Set the orientation and alignment for the dialog.
dialog.orientation = 'column';
dialog.alignChildren = 'fill';
dialog.spacing = 10;
dialog.preferredSize.width = 1000;
var sourcePanel = dialog.add('panel', undefined, 'Source Files');
sourcePanel.orientation = 'column';
sourcePanel.alignChildren = 'fill';
sourcePanel.preferredSize.width = dialog.preferredSize.width;
var btnSourceFiles = sourcePanel.add('button', undefined, 'Select Files...');
var btnSourceFolder = sourcePanel.add('button', undefined, 'Select Folder...');
// Listbox to display the selected files with headers for file name and path.
var fileList = sourcePanel.add('listbox', undefined, [], {
multiselect: true,
numberOfColumns: 2,
showHeaders: true,
columnTitles: ['File Name', 'Path'],
columnWidths: [sourcePanel.preferredSize.width * 0.6, sourcePanel.preferredSize.width * 0.4]
});
fileList.preferredSize.height = 250;
var outputAndSettingsPanel = dialog.add('panel', undefined, 'Output and Settings');
outputAndSettingsPanel.orientation = 'row';
outputAndSettingsPanel.alignChildren = 'top';
outputAndSettingsPanel.spacing = 10;
outputAndSettingsPanel.preferredSize.width = dialog.preferredSize.width;
var outputPanel = outputAndSettingsPanel.add('panel', undefined, 'Output');
outputPanel.orientation = 'column';
outputPanel.alignChildren = 'fill';
outputPanel.preferredSize.width = Math.round(outputAndSettingsPanel.preferredSize.width / 3);
outputPanel.add('statictext', undefined, 'Select output folder:');
var btnOutputFolder = outputPanel.add('button', undefined, 'Select Folder...');
var outputText = outputPanel.add('edittext', undefined, '');
outputText.size = [outputPanel.preferredSize.width - 30, 20];
btnSourceFiles.onClick = function() {
// Handler for the "Select Files..." button click
var files = File.openDialog("Select files", "All files:*.jpg;*.jpeg;*.png;*.psd;*.tiff;*.tif", true);
if (files) {
dialog.sourceFiles = dialog.sourceFiles ? dialog.sourceFiles.concat(files) : files;
updateFileListUI(fileList, dialog.sourceFiles);
}
};
btnSourceFolder.onClick = function() {
// Handler for the "Select Folder..." button click
var folder = Folder.selectDialog("Select a folder");
if (folder) {
dialog.sourceFolder = folder;
var folderFiles = getFilesFromSource(folder, null);
updateFileListUI(fileList, folderFiles);
}
};
btnOutputFolder.onClick = function() {
// Handler for the "Select Folder..." button click in the Output panel
var folder = Folder.selectDialog("Select output folder");
if (folder) {
outputText.text = folder.fsName;
dialog.outputFolder = folder;
}
};
// Function to update the file list UI
function updateFileListUI(fileList, files) {
fileList.removeAll(); // Clear the existing list
for (var i = 0; i < files.length; i++) {
var file = files[i];
var item = fileList.add('item', file.name);
item.subItems[0].text = file.fsName;
}
}
var buttonsGroup = dialog.add('group');
buttonsGroup.orientation = 'row';
buttonsGroup.alignChildren = 'center';
// OK button to start processing.
var btnOk = buttonsGroup.add('button', undefined, 'OK', {name: 'ok'});
btnOk.onClick = function() {
// Handler for the OK button click
dialog.close(1); // Close the dialog and proceed with processing.
};
var btnCancel = buttonsGroup.add('button', undefined, 'Cancel', {name: 'cancel'});
btnCancel.onClick = function() {
// Handler for the Cancel button click
dialog.close(0); // Close the dialog and cancel processing.
};
// Assign dialog properties
dialog.sourceFolder = null; // Initially, no source folder is selected
dialog.outputFolder = null; // Initially, no output folder is selected
dialog.preserveInputFormat = true; // Initially, preserve the input format
dialog.outputFormat = 'JPG'; // Default output format
dialog.resampleMethod = 'None'; // Default resample method
dialog.deleteSourceFiles = false; // Default setting for deleting source files
return dialog;
}
function createSettingsDialog() {
var settingsDialog = new Window('dialog', 'Settings');
settingsDialog.orientation = 'column';
settingsDialog.alignChildren = 'center';
settingsDialog.spacing = 10;
settingsDialog.margins = 10;
var exportSettingsPanel = settingsDialog.add('panel', undefined, 'Export Settings');
exportSettingsPanel.orientation = 'column';
exportSettingsPanel.alignChildren = 'fill';
exportSettingsPanel.spacing = 5;
var outputFolderGroup = exportSettingsPanel.add('group');
outputFolderGroup.orientation = 'row';
outputFolderGroup.add('statictext', undefined, 'Output Folder:');
var outputFolderEditText = outputFolderGroup.add('edittext', undefined, getSetting('outputFolder'));
outputFolderEditText.preferredSize.width = 200;
var outputFolderButton = outputFolderGroup.add('button', undefined, 'Browse...');
outputFolderButton.onClick = function() {
var selectedFolder = Folder.selectDialog("Select an output folder");
if (selectedFolder) {
// Set the text of the output folder edit text to the path of the selected folder.
outputFolderEditText.text = selectedFolder.fsName;
// Save the selected folder path as the new output folder setting.
saveSetting('outputFolder', selectedFolder.fsName);
}
};
var resampleMethodGroup = exportSettingsPanel.add('group');
resampleMethodGroup.orientation = 'row';
resampleMethodGroup.add('statictext', undefined, 'Resample Method:');
var resampleMethodDropdown = resampleMethodGroup.add('dropdownlist', undefined, ['Automatic', 'Bicubic', 'Bilinear', 'Nearest Neighbor', 'None']);
resampleMethodDropdown.selection = resampleMethodDropdown.find(getSetting('resampleMethod'));
var preserveFormatGroup = exportSettingsPanel.add('group');
preserveFormatGroup.orientation = 'row';
var preserveInputFormatCheckbox = preserveFormatGroup.add('checkbox', undefined, 'Preserve Input Format');
preserveInputFormatCheckbox.value = getSetting('preserveInputFormat');
var outputFormatDropdown = preserveFormatGroup.add('dropdownlist', undefined, ['JPG', 'PNG', 'TIFF']);
outputFormatDropdown.selection = outputFormatDropdown.find(getSetting('outputFormat'));
outputFormatDropdown.enabled = !preserveInputFormatCheckbox.value;
var jpegQualityGroup = exportSettingsPanel.add('group');
jpegQualityGroup.orientation = 'row';
jpegQualityGroup.add('statictext', undefined, 'JPG Quality:');
var jpegQualitySlider = jpegQualityGroup.add('slider', undefined, getSetting('jpegQuality'), 1, 12);
var jpegQualityValueLabel = jpegQualityGroup.add('statictext', undefined, jpegQualitySlider.value.toString());
jpegQualitySlider.onChanging = function() {
jpegQualityValueLabel.text = Math.round(this.value).toString();
};
jpegQualityGroup.visible = preserveInputFormatCheckbox.value || getSetting('outputFormat') === 'JPG';
var exportSettingsButtonsGroup = exportSettingsPanel.add('group');
exportSettingsButtonsGroup.orientation = 'row';
var saveExportSettingsButton = exportSettingsButtonsGroup.add('button', undefined, 'Save Export Settings');
var revertExportSettingsButton = exportSettingsButtonsGroup.add('button', undefined, 'Revert to Default Settings');
var advancedSettingsPanel = settingsDialog.add('panel', undefined, 'Advanced Settings');
advancedSettingsPanel.orientation = 'column';
advancedSettingsPanel.alignChildren = 'fill';
advancedSettingsPanel.spacing = 5;
// Analysis Area Size with description
var analysisAreaSizeGroup = advancedSettingsPanel.add('group');
analysisAreaSizeGroup.orientation = 'row';
analysisAreaSizeGroup.add('statictext', undefined, 'Analysis Area Size:');
var analysisAreaSizeEditText = analysisAreaSizeGroup.add('edittext', undefined, getSetting('analysisAreaSize'));
analysisAreaSizeEditText.preferredSize.width = 50;
var analysisAreaSizeDescription = advancedSettingsPanel.add('statictext', undefined, 'The size of the area (in pixels) used for color analysis.');
analysisAreaSizeDescription.graphics.font = ScriptUI.newFont("dialog", "Italic", 10);
var numberOfSampleAreasGroup = advancedSettingsPanel.add('group');
numberOfSampleAreasGroup.orientation = 'row';
numberOfSampleAreasGroup.add('statictext', undefined, 'Number of Sample Areas:');
var numberOfSampleAreasEditText = numberOfSampleAreasGroup.add('edittext', undefined, getSetting('numberOfSampleAreas'));
numberOfSampleAreasEditText.preferredSize.width = 50;
var numberOfSampleAreasDescription = advancedSettingsPanel.add('statictext', undefined, 'The number of areas sampled for color analysis across the image.');
numberOfSampleAreasDescription.graphics.font = ScriptUI.newFont("dialog", "Italic", 10);
var outlierThresholdsGroup = advancedSettingsPanel.add('group');
outlierThresholdsGroup.orientation = 'row';
outlierThresholdsGroup.add('statictext', undefined, 'Outlier Thresholds:');
// ... (dual-slider code)
var outlierThresholdsDescription = advancedSettingsPanel.add('statictext', undefined, 'The low and high percentage thresholds for excluding outlier values from analysis.');
outlierThresholdsDescription.graphics.font = ScriptUI.newFont("dialog", "Italic", 10);
var lowOutlierThresholdSlider = outlierThresholdsGroup.add('slider', undefined, getSetting('outlierThresholds').low, 1, 100);
lowOutlierThresholdSlider.value = getSetting('outlierThresholds').low || 35; // Default to 35 if not set
var lowOutlierThresholdValueLabel = outlierThresholdsGroup.add('statictext', undefined, lowOutlierThresholdSlider.value.toString());
var highOutlierThresholdSlider = outlierThresholdsGroup.add('slider', undefined, getSetting('outlierThresholds').high, 1, 100);
highOutlierThresholdSlider.value = getSetting('outlierThresholds').high || 65; // Default to 65 if not set
var highOutlierThresholdValueLabel = outlierThresholdsGroup.add('statictext', undefined, highOutlierThresholdSlider.value.toString());
lowOutlierThresholdSlider.onChanging = function() {
if (lowOutlierThresholdSlider.value > highOutlierThresholdSlider.value) {
highOutlierThresholdSlider.value = lowOutlierThresholdSlider.value;
}
lowOutlierThresholdValueLabel.text = Math.round(lowOutlierThresholdSlider.value).toString();
};
highOutlierThresholdSlider.onChanging = function() {
if (highOutlierThresholdSlider.value < lowOutlierThresholdSlider.value) {
lowOutlierThresholdSlider.value = highOutlierThresholdSlider.value;
}
highOutlierThresholdValueLabel.text = Math.round(highOutlierThresholdSlider.value).toString();
};
var advancedSettingsButtonsGroup = advancedSettingsPanel.add('group');
advancedSettingsButtonsGroup.orientation = 'row';
var saveAdvancedSettingsButton = advancedSettingsButtonsGroup.add('button', undefined, 'Save Advanced Settings');
var revertAdvancedSettingsButton = advancedSettingsButtonsGroup.add('button', undefined, 'Revert to Default Settings');
saveExportSettingsButton.onClick = function() {
saveSetting('outputFolder', outputFolderEditText.text);
saveSetting('resampleMethod', resampleMethodDropdown.selection.text);
saveSetting('preserveInputFormat', preserveInputFormatCheckbox.value);
saveSetting('outputFormat', outputFormatDropdown.selection.text);
saveSetting('jpegQuality', parseInt(jpegQualityValueLabel.text));
settingsDialog.close();
};
revertExportSettingsButton.onClick = function() {
// Revert Export Settings to Default
revertToDefaultSettings();
settingsDialog.close();
};
saveAdvancedSettingsButton.onClick = function() {
// Save Advanced Settings
saveSetting('analysisAreaSize', parseInt(analysisAreaSizeEditText.text));
saveSetting('numberOfSampleAreas', parseInt(numberOfSampleAreasEditText.text));
saveSetting('outlierThresholds', {
low: parseInt(lowOutlierThresholdValueLabel.text),
high: parseInt(highOutlierThresholdValueLabel.text)
});
settingsDialog.close();
};
revertAdvancedSettingsButton.onClick = function() {
// Revert Advanced Settings to Default
revertToDefaultSettings();
settingsDialog.close();
};
var navigationGroup = settingsDialog.add('group');
navigationGroup.orientation = 'row';
var returnButton = navigationGroup.add('button', undefined, 'Return to Script');
var closeButton = navigationGroup.add('button', undefined, 'Close');
returnButton.onClick = function() {
settingsDialog.close();
};
closeButton.onClick = function() {
// Close the settings dialog
settingsDialog.close();
};
return settingsDialog;
}
function processFiles(files, progressBar, outputFolder, preserveInputFormat, outputFormat, jpegQuality, resampleMethod, analysisSize, deleteSourceFiles) {
var totalFiles = files.length; // Total number of files to process
progressBar.macroBar.value = 0; // Initialize the macro progress bar to 0%
progressBar.macroBar.maxvalue = 100; // Set the maximum value of the macro progress bar to 100
// Loop through each file in the list of files to be processed
for (var i = 0; i < totalFiles; i++) {
var file = files[i]; // Get the current file from the list
var fileIndex = i + 1; // Current file index (1-based for display purposes)
// Open the current document in Photoshop
var doc = openDocument(file);
app.runMenuItem(stringIDToTypeID('fitOnScreen'));
app.refresh(); // Refresh the Photoshop UI to reflect the zoom change
progressBar.stMessage.text = "Analyzing Pixels of file " + fileIndex + " of " + totalFiles;
progressBar.microBar.value = 25; // Set micro progress bar to 25% after opening the document
progressBar.macroBar.value = ((fileIndex / totalFiles) * 100) + 0;
app.refresh(); // Refresh the UI to show the updated progress bar and message
analyzeAndResize(doc, analysisSize, resampleMethod);
progressBar.microBar.value = 50; // Set micro progress bar to 50% after analysis
progressBar.stMessage.text = "Resizing file " + fileIndex + " of " + totalFiles;
progressBar.macroBar.value = ((fileIndex / totalFiles) * 100) + 1;
app.refresh(); // Refresh the UI
saveDocument(doc, file, outputFolder, preserveInputFormat, outputFormat, jpegQuality);
progressBar.microBar.value = 75; // Set micro progress bar to 75% after saving
progressBar.stMessage.text = "Saved file " + fileIndex + " of " + totalFiles;
progressBar.macroBar.value = ((fileIndex / totalFiles) * 100) + 2;
app.refresh(); // Refresh the UI
doc.close(SaveOptions.DONOTSAVECHANGES);
progressBar.microBar.value = 100; // Set micro progress bar to 100% after closing
progressBar.stMessage.text = "Closed file " + fileIndex + " of " + totalFiles;
progressBar.macroBar.value = ((fileIndex / totalFiles) * 100) + 3;
app.refresh(); // Refresh the UI
if (deleteSourceFiles) {
file.remove();
}
progressBar.stMessage.text = "Processed file " + fileIndex + " of " + totalFiles;
app.refresh(); // Refresh the UI after processing each file
}
progressBar.stMessage.text = "Processing complete.";
progressBar.macroBar.value = 100;
app.refresh(); // Final UI refresh after all files are processed
}
// Function to open a document in Photoshop.
function openDocument(file) {
return app.open(file);
}
function analyzeAndResize(doc, analysisSize, resampleMethod) {
var width = doc.width.as('px');
var height = doc.height.as('px');
var allRowColorCounts = analyzeDocument(doc, width, height, analysisSize);
var scaleFactor = calculateScaleFactor(allRowColorCounts);
resizeDocument(doc, scaleFactor, resampleMethod);
}
// Function to analyze the document and return color counts.
function analyzeDocument(doc, width, height, analysisSize) {
var allRowColorCounts = [];
var numSampleAreas = getSetting('numberOfSampleAreas'); // Add this line
var positions = calculateSamplePositions(width, height, analysisSize, numSampleAreas); // Use the retrieved value here
for (var i = 0; i < positions.length; i++) {
var startX = positions[i][0];
var startY = positions[i][1];
for (var y = startY; y < startY + analysisSize; y++) {
var uniqueColors = {};
for (var x = startX; x < startX + analysisSize; x++) {
var pixelLoc = [UnitValue(x, 'px'), UnitValue(y, 'px')];
var colorSampler = doc.colorSamplers.add(pixelLoc);
var color = colorSampler.color;
var colorKey = color.rgb.hexValue;
uniqueColors[colorKey] = true;
colorSampler.remove();
}
var colorCount = Object.keys(uniqueColors).length;
allRowColorCounts.push(colorCount);
}
}
return allRowColorCounts;
}
// Function to calculate the scale factor based on color counts.
function calculateScaleFactor(allRowColorCounts) {
var outlierThresholds = getSetting('outlierThresholds'); // Retrieve outlier thresholds
var analysisSize = getSetting('analysisAreaSize'); // Retrieve analysis area size
var lowerBound = Math.floor(allRowColorCounts.length * (outlierThresholds.low / 100));
var upperBound = Math.ceil(allRowColorCounts.length * (outlierThresholds.high / 100));
var validCounts = allRowColorCounts.slice(lowerBound, upperBound);
var sum = validCounts.reduce(function(a, b) { return a + b; }, 0);
var avgColorCount = sum / validCounts.length;
return avgColorCount / analysisSize; // Use the retrieved analysis area size here
}
// Function to resize the document.
function resizeDocument(doc, scaleFactor, resampleMethod) {
var resampleMethodEnum;
switch (resampleMethod) {
case 'Bicubic':
resampleMethodEnum = ResampleMethod.BICUBIC;
break;
case 'Bilinear':
resampleMethodEnum = ResampleMethod.BILINEAR;
break;
case 'Nearest Neighbor':
resampleMethodEnum = ResampleMethod.NEARESTNEIGHBOR;
break;
case 'None':
resampleMethodEnum = undefined;
break;
default:
resampleMethodEnum = ResampleMethod.AUTOMATIC;
break;
}
var newWidth = doc.width.as('px') * scaleFactor;
var newHeight = doc.height.as('px') * scaleFactor;
if (resampleMethodEnum !== undefined) {
doc.resizeImage(UnitValue(newWidth, 'px'), UnitValue(newHeight, 'px'), doc.resolution, resampleMethodEnum);
} else {
doc.resizeImage(UnitValue(newWidth, 'px'), UnitValue(newHeight, 'px'), doc.resolution);
}
}
// Function to save the document with the specified settings.
function saveDocument(doc, originalFile, outputFolder, preserveInputFormat, outputFormat, jpegQuality) {
// Determines the file path and save options based on user settings and saves the document.
var saveFile = determineOutputFile(originalFile, outputFolder, preserveInputFormat, outputFormat);
var saveOptions = determineSaveOptions(saveFile, jpegQuality);
doc.saveAs(saveFile, saveOptions, true);
}
function determineOutputFile(originalFile, outputFolder, preserveInputFormat, outputFormat) {
var filename = originalFile.name.replace(/\.[^\.]+$/, ''); // Strip the original extension
var extension = preserveInputFormat ? originalFile.name.split('.').pop().toLowerCase() : outputFormat.toLowerCase(); // Ensure the extension is lowercase
var newFilePath = outputFolder + "/" + filename + "." + extension; // Construct the new file path
return new File(newFilePath);
}
// Function to determine the save options based on the file type.
function determineSaveOptions(saveFile, jpegQuality) {
// Selects the appropriate save options for the output file based on its format.
var saveOptions;
var extension = saveFile.name.split('.').pop().toLowerCase(); // Get the file extension
switch (extension) {
case 'jpg':
case 'jpeg':
saveOptions = new JPEGSaveOptions();
saveOptions.quality = jpegQuality;
break;
case 'png':
saveOptions = new PNGSaveOptions();
break;
case 'tiff':
saveOptions = new TiffSaveOptions();
break;
default:
saveOptions = new PhotoshopSaveOptions();
break;
}
return saveOptions;
}
// Function to calculate positions for sampling squares within the document.
function calculateSamplePositions(width, height, squareSize, numSamples) {
// Calculates the positions where color sampling will occur for analysis, based on the document dimensions.
var positions = [];
var cols = Math.ceil(Math.sqrt(numSamples)); // Determine the number of columns needed
var rows = Math.ceil(numSamples / cols); // Determine the number of rows needed
var spacingX = width / (cols + 1); // Calculate horizontal spacing between samples
var spacingY = height / (rows + 1); // Calculate vertical spacing between samples
// Loop through each row and column to calculate sample positions
for (var row = 1; row <= rows; row++) {
for (var col = 1; col <= cols; col++) {
var posX = spacingX * col - squareSize / 2;
var posY = spacingY * row - squareSize / 2;
positions.push([posX, posY]); // Add the position to the array
}
}
return positions.slice(0, numSamples); // Return only the number of samples needed
}
// The main entry point for the script execution.
(function main() {
// Create and display the main dialog.
var dialog = createDialog();
// Show the dialog and store the result (1 for OK, 2 for Cancel).
var result = dialog.show();
// If the user clicked OK, proceed with processing.
if (result === 1) {
// Retrieve the user's selections from the dialog.
var sourceFolder = dialog.sourceFolder;
var outputFolder = getSetting('outputFolder');
var preserveInputFormat = getSetting('preserveInputFormat');
var outputFormat = getSetting('outputFormat');
var jpegQuality = getSetting('jpegQuality');
var resampleMethod = getSetting('resampleMethod');
var deleteSourceFiles = getSetting('deleteSourceFiles');
var analysisSize = getSetting('analysisAreaSize');
var files = getFilesFromSource(sourceFolder, dialog.sourceFiles);
// If no files are selected, alert the user and exit the script.
if (files.length === 0) {
alert("No files selected for processing.");
return;
}
var progressBar = createProgressWindow("Processing Images", files.length);
// Process each file.
processFiles(files, progressBar, outputFolder, preserveInputFormat, outputFormat, jpegQuality, resampleMethod, analysisSize, deleteSourceFiles);
progressBar.close();
}
})();
function createProgressWindow(title, maxValue) {
var win = new Window('palette', title);
win.alignChildren = 'fill';
// Add a static text label for the overall progress bar (macro).
win.add('statictext', undefined, 'Overall Progress:');
// Create the macro progress bar with a range from 0 to the total number of files.
win.macroBar = win.add('progressbar', undefined, 0, maxValue);
win.macroBar.preferredSize = [400, 20];
// Add a static text label for the current file progress bar (micro).
win.add('statictext', undefined, 'Current File Progress:');
// Create the micro progress bar with a range from 0 to 100.
win.microBar = win.add('progressbar', undefined, 0, 100);
win.microBar.preferredSize = [400, 20];
// Set the initial value of the macro progress bar to 0%.
win.macroBar.value = 0;
// Static text for displaying messages about the current operation.
win.stMessage = win.add('statictext');
win.stMessage.preferredSize.width = 400;
// Function to update the progress bars and message text.
win.updateProgress = function (macroValue, microValue, message) {
// Update the macro progress bar's value.
this.macroBar.value = macroValue;
// Update the micro progress bar's value.
this.microBar.value = microValue;
// Update the message text to inform the user of the current operation.
this.stMessage.text = message;
// Refresh the window to reflect the changes.
this.update();
};
// Show the progress window.
win.show();
return win;
}