@leol30
EDIT: Script updated to version 1.1 where files that fail the test for neutrality are moved to a "Rejected" folder.
This Photoshop script will process the root/top-level of an input folder for supported files and will log files to the desktop in a text file that have a Standard Deviation value for the sum of the a+b channels that is greater than 0.00 (0.00 being fully neutral).
You can adjust the tolerance/threshold for neutral values from the default 0.00 by adjusting the following line of code:
This script is more a proof of concept than anything, but it may be useful if you can come up with a suitable Std. Dev. value that accounts for the colour artefacts introduced by JPEG compression. The Mean or Median values of combined or single a & b channels could also be used instead.
If this does prove useful I am happy to make changes to the script.
P.S. I am more comfortable scripting Photoshop than Bridge, which is why this is a Photoshop script, despite this topic being on in the Bridge forum.
Here is the full script for Photoshop:
/*
Batch Log Non-Neutral B&W Files from Input Folder.jsx
https://community.adobe.com/t5/bridge-discussions/script-to-find-colour-in-quot-black-amp-white-quot-jpgs/td-p/14141472
v1.1 - 11th October 2023, Stephen Marsh
Info:
This Photoshop script will process the root/top-level of an input folder
for supported files and will log files to the desktop in a text file
that have a Standard Deviation value for the sum of the a+b channels
that is greater than 0.00 (0.00 being fully neutral). A new folder
named "Rejected" will be created in the input folder and documents
which fail will be moved to this folder.
*/
#target photoshop
if (app.documents.length === 0) {
// Select the folder containing the files
var inputFolder = Folder.selectDialog("Select the input folder", "");
// Add or remove supported file extensions as required
var inputFiles = inputFolder.getFiles(/\.(jpg|jpeg|tif|tiff|psd|psb|png|bmp|webp|tga)$/i);
inputFiles.sort();
// Set the input file counter
var inputFileCounter = 0;
// Set the failed file counter
var failedCounter = 0;
// Initial log file entries
var dateTime = new Date().toLocaleString();
var logFile = new File("~/Desktop/Neutral File Evaluation.log");
if (logFile.exists)
logFile.remove();
var os = $.os.toLowerCase().indexOf("mac") >= 0 ? "mac" : "windows";
if (os === "mac") {
var logFileLF = "Unix";
} else {
logFileLF = "Windows";
}
logFile.open("w");
logFile.encoding = "UTF-8";
logFile.lineFeed = logFileLF;
logFile.writeln(dateTime);
logFile.writeln(inputFolder.fsName + "/" + "Rejects" + "/");
logFile.close();
// Process the files
for (var i = 0; i < inputFiles.length; i++) {
open(inputFiles[i]);
// Convert to Lab mode
activeDocument.changeMode(ChangeMode.LAB);
// Histogram evaluation
var aCha = theHistProps(activeDocument.channels[1].histogram);
var bCha = theHistProps(activeDocument.channels[2].histogram);
// theMean = [0] | theMedian = [1] | theStandDev = [2]
var theValue = (((aCha[2] + bCha[2]) / 2).toFixed(2));
/* Change neutral target value as required */
if (theValue > 0.00) {
// Rejected files variables and folder
var theDoc = activeDocument;
var theName = theDoc.name;
var theFolder = Folder(theDoc.path + "/" + "Rejects");
if (!theFolder.exists) {
theFolder.create()
}
try {
writeFailedLogEntry();
failedCounter++;
// Copy the rejected files
File(theDoc.fullName).copy(theFolder + "/" + theName);
// Remove the original files
theDoc.fullName.remove();
} catch (e) {}
// Close without saving
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
} else {
// Close without saving
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
inputFileCounter++;
}
// End of script notification
alert(inputFileCounter + " files processed:" + "\r" + failedCounter + " files failed");
} else {
alert('No documents should be open when running this script!');
}
///// FUNCTIONS /////
function writeFailedLogEntry() {
var os = $.os.toLowerCase().indexOf("mac") >= 0 ? "mac" : "windows";
if (os === "mac") {
var logFileLF = "Unix";
} else {
logFileLF = "Windows";
}
logFile.open("a");
logFile.encoding = "UTF-8";
logFile.lineFeed = logFileLF;
logFile.writeln("FAILED = (" + theValue + ") " + activeDocument.name + "\r");
logFile.close();
}
function theHistProps(theHist) {
/* Based on https://community.adobe.com/t5/photoshop/how-to-get-the-histogram-s-std-dev/td-p/9875041 */
// get total number;
var thePixels = 0;
for (var m = 0; m < theHist.length; m++) {
thePixels = thePixels + theHist[m];
}
// get mean and median
var theMean = 0;
var aTotal = 0;
var check = false;
for (var n = 0; n < theHist.length; n++) {
theMean = theMean + (n * theHist[n] / thePixels);
aTotal = aTotal + theHist[n];
if (aTotal >= thePixels / 2 && check === false) {
theMedian = n;
check = true;
}
}
// get standard deviation
var theStandDev = 0;
for (var o = 0; o < theHist.length; o++) {
theStandDev = theStandDev + (Math.pow((o - theMean), 2) * theHist[o]);
}
theStandDev = Math.sqrt(theStandDev / thePixels);
// Return the properties: theMean = [0] | theMedian = [1] | theStandDev = [2]
return ([theMean, theMedian, theStandDev]);
}
- 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