-
-
Save jaap/f097d07ebbdd51fe5f6b4e743a110b46 to your computer and use it in GitHub Desktop.
| // cropAndStraightenBatch.jsx | |
| // Copyright 2006-2008 | |
| // Written by Jeffrey Tranberry | |
| // Photoshop for Geeks Version 2.0 | |
| /* | |
| Description: | |
| This script demonstates how to batch process | |
| a folder of images using the crop and straighten command | |
| */ | |
| // enable double clicking from the | |
| // Macintosh Finder or the Windows Explorer | |
| #target photoshop | |
| // Make Photoshop the frontmost application | |
| // in case we double clicked the file | |
| app.bringToFront(); | |
| ///////////////////////// | |
| // SETUP | |
| ///////////////////////// | |
| // A list of file extensions to skip, keep them lower case | |
| gFilesToSkip = Array( "db", "xmp", "thm", "txt", "doc", "md0", "tb0", "adobebridgedb", "adobebridgedbt", "bc", "bct" ); | |
| ///////////////////////// | |
| // MAIN | |
| ///////////////////////// | |
| main(); | |
| function main() { | |
| //Make sure there are no open documents | |
| if (app.documents.length > 0){ | |
| alert ("This script requires that there are no open documents to run."); | |
| }else{ | |
| // Pops open a dialog for the user to choose the folder of documents to process | |
| var inputFolder = Folder.selectDialog("Select a folder of documents to process"); | |
| // Pops open a dialog for the user to set the output folder | |
| var outputFolder = Folder.selectDialog("Select a folder for the output files"); | |
| // Check to make sure outputfolder is not in inputFolder | |
| if(outputFolderIsOk(inputFolder, outputFolder) === false){ | |
| alert("Your output folder should not be within your input folder. It will create an infinitive loop."); | |
| return; | |
| } | |
| // Open and process a folder of Images | |
| OpenFolderRecursively(inputFolder, outputFolder); | |
| } | |
| } | |
| ///////////////////////// | |
| // FUNCTIONS | |
| ///////////////////////// | |
| // Given the a Folder of files, open the files and process them | |
| function OpenFolderRecursively(inputFolder, outputFolder) { | |
| var filesOpened = 0; | |
| var fileList = inputFolder.getFiles(); | |
| for ( var i = 0; i < fileList.length; i++ ) { | |
| // Make sure all the files in the folder are compatible with PS | |
| if ( fileList[i] instanceof File && ! fileList[i].hidden && ! IsFileOneOfThese( fileList[i], gFilesToSkip )) { | |
| open( fileList[i] ); | |
| filesOpened++; | |
| ///////////////////////// | |
| // Put all your processing functions... | |
| ///////////////////////// | |
| // Create a variable to store a reference to | |
| // the currently active document, which in this | |
| // case is the parent document we want to extract | |
| // multiple scanned images from | |
| var docRef = app.activeDocument; | |
| // Run the cropAndStraighten function | |
| // which will rusult in more than one open document | |
| try { | |
| cropAndStraighten(); | |
| } catch (error) { | |
| // Skip cropping, image incompatible | |
| } | |
| // Close the parent document we originally opened | |
| docRef.close(SaveOptions.DONOTSAVECHANGES); | |
| // Process all open documents until no documents | |
| // are left open. | |
| while (app.documents.length >=1){ | |
| ///////////////////////// | |
| // Put all your processing functions... | |
| ///////////////////////// | |
| // Flatten the document in case the file type we want to save to requires a flat doc | |
| app.activeDocument.flatten(); | |
| //Save as a JPEG to the outputFolder | |
| var jpegOptions = new JPEGSaveOptions(); | |
| jpegOptions.quality = 12; | |
| jpegOptions.embedColorProfile = false; | |
| app.activeDocument.saveAs( File( outputFolder + "/" + activeDocument.name + ".jpg"), jpegOptions, false); | |
| // Close without saving | |
| app.activeDocument.close(SaveOptions.DONOTSAVECHANGES); | |
| ///////////////////////// | |
| // ...in the area between these two comments. | |
| ///////////////////////// | |
| } | |
| ///////////////////////// | |
| // ...in the area between these two comments. | |
| ///////////////////////// | |
| } | |
| // go recursive | |
| if (!(fileList[i] instanceof File)) { | |
| var newOuputFolder = new Folder(outputFolder + "/" + new Folder(fileList[i]).name); | |
| newOuputFolder.create(); | |
| OpenFolderRecursively(fileList[i], newOuputFolder); | |
| } | |
| } | |
| return filesOpened; | |
| } | |
| // given a file name and a list of extensions | |
| // determine if this file is in the list of extensions | |
| function IsFileOneOfThese( inFileName, inArrayOfFileExtensions ) { | |
| var lastDot = inFileName.toString().lastIndexOf( "." ); | |
| if ( lastDot == -1 ) { | |
| return false; | |
| } | |
| var strLength = inFileName.toString().length; | |
| var extension = inFileName.toString().substr( lastDot + 1, strLength - lastDot ); | |
| extension = extension.toLowerCase(); | |
| for (var i = 0; i < inArrayOfFileExtensions.length; i++ ) { | |
| if ( extension == inArrayOfFileExtensions[i] ) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // Crop and Straighten function created | |
| // using the ScriptingListener plug-in | |
| function cropAndStraighten(){ | |
| var id333 = stringIDToTypeID( "CropPhotosAuto0001" ); | |
| executeAction( id333, undefined, DialogModes.NO ); | |
| } | |
| // Validate output is outside input folder | |
| function outputFolderIsOk(inputFolder, outputFolder){ | |
| inputFolderString = inputFolder.absoluteURI; | |
| outputFolderString = outputFolder.absoluteURI; | |
| if(inputFolderString === outputFolderString){ | |
| return false; | |
| } | |
| if(isChildFolderOf(outputFolderString, inputFolderString)){ | |
| return false; | |
| } | |
| return true; | |
| } | |
| function isChildFolderOf(outputFolderString, inputFolderString) { | |
| inputFolders = inputFolderString.split('/'); | |
| outputFolders = outputFolderString.split('/'); | |
| // Impossible to be child | |
| if(inputFolders.length > outputFolders.length){ | |
| return false; | |
| } | |
| lastFolderIndex = inputFolders.length - 1; | |
| lastInputFolder = inputFolders[lastFolderIndex]; | |
| if(outputFolders[lastFolderIndex] === lastInputFolder){ | |
| return true; | |
| } | |
| return false; | |
| } |
jaap
commented
Jan 14, 2022
- Made the script continue when it has an image it can't work with (resulted in a crash before)
- Added a check to make sure the output folder is not the same or within the input folder (@atav32 's suggestion)
- Set jpg quality to 12 (max)
this is so great - question: I'm sure you're very busy but I would be eternally grateful if you could add/recommend a function to add a uniform margin/buffer to the crop and straighten function? I find that for some images PS crops a bit too close, like right to the edge, but I want to have a slight border (fyi, this is for pictures of sports cards taken in a light box with as black of a background as I could find.)
UPDATE - I asked ChatGPT(-4) for help, and it's suggestions seemed to work. In case you or future travelers are curious, I forked your script and included these suggestions. Thanks again for posting this work.
This function expands the selection by 2px:
function expandSelectionBy(pixels) {
var doc = app.activeDocument;
// We assume a selection exists
var bounds = doc.selection.bounds;
var x1 = bounds[0] - pixels;
var y1 = bounds[1] - pixels;
var x2 = bounds[2] + pixels;
var y2 = bounds[3] + pixels;
doc.selection.select([[x1, y1], [x2, y1], [x2, y2], [x1, y2]]);
}
... and this updates the cropAndStraighten function to incorporate the selection expansion:
function cropAndStraighten(){
var id333 = stringIDToTypeID("CropPhotosAuto0001");
executeAction(id333, undefined, DialogModes.NO);
// After executing the cropAndStraighten action, adjust the active selection
expandSelectionBy(2);
// Crop the image based on the modified selection
app.activeDocument.crop(app.activeDocument.selection.bounds);
}