// philg-pscs2-processor.jsx.txt.jsx
// from http://photo.net/learn/photoshop/
// tested with Adobe Photoshop versions CS2 through CS5
// updated July 5, 2010 based on a script from April 2, 2009
// by philg@mit.edu based on a script from a kind soul at Adobe
// this script requires the installation of fonts named "9x15" and "6x13"; these are fixed-pitch ASCII terminal-style
// fonts from the X Windows system. You can use other fonts but I was never able to get the letters to be legible
// maybe because Photoshop is always trying to do fancy anti-aliasing. These fonts are available for Windows from
// http://philip.greenspun.com/photography/photoshop-scripts/
// April 2, 2009: fixed failure to run with CS4/CS5
// prior latest addition is that if it doesn't start with a .JPG, this writes
// a JPEG file that is just as large as the camera original (good for huge
// monitors)
// February 17, 2006: added "info" to the list of extensions to skip,
// thus working around a problem created by using Canon's Zoom Browser,
// which leaves behind a ZbThumbnail.info file in each folder
// this sets the debug level, 0 means debugger off, 1 is on
$.level = 1;
// set to false if you don't want them
var debug_alerts = false;
if (debug_alerts) {
alert("will run with debug alerts");
}
var gVersion = 4;
// a global variable for the title of the dialog
// this string will also be used for the preferences file I write to disk
// Photoshop Install Directory/Presets/JPEGenator/RawToJPEGs.xml for example
var gScriptName = "RawToJPEGs";
// A list of file extensions I will skip, keep them lower case
var gFilesToSkip = Array( "db", "xmp", "thm", "htm", "txt", "doc", "md0", "tb0", "dat", "info" );
// A list of camera raw extensions, keep them lower case
var gFilesForCameraRaw = Array( "tif", "crw", "nef", "raf", "orf", "mrw", "dcr", "mos", "srf", "pef", "dcr" );
// limit the length of text in edit boxes by this length
var gShortFileNameLengthWin = 30;
var gShortFileNameLengthMac = 22;
var gShortFileNameLength = gShortFileNameLengthMac;
// remember some things
var gStartRulerUnits = preferences.rulerUnits;
var gStartTypeUnits = preferences.typeUnits;
var gStartDisplayDialogs = displayDialogs;
// Set Photoshop to use pixels and display no dialogs
preferences.rulerUnits = Units.PIXELS;
preferences.typeUnits = TypeUnits.PIXELS;
displayDialogs = DialogModes.NO;
// global parameters
var gParams = null;
// the main routine
// the ImageProcessor class does most of the work
try {
CheckVersion();
if ( IsWindowsOS() ) {
gShortFileNameLength = gShortFileNameLengthWin;
}
var gIP = new ImageProcessor();
// load my preferences from disk
LoadParamsFromDisk( GetDefaultParamsFile(), gParams );
// run without the dialog
if ( gParams["dialogsoff"] ) {
// don't bother with the dialog or saving the params
gIP.Execute();
} else {
// run with the dialog
if ( gIP.RunDialog() ) {
// execute accordingly
gIP.Execute();
// write my params back to disk for the next run
SaveParamsToDisk( GetDefaultParamsFile(), gParams );
}
}
}
// Lot's of things can go wrong, Give a generic alert and see if they want the details
catch(e) {
if ( confirm("Sorry, something major happened and I can't continue! Would you like to see more info?" ) ) {
alert(e);
}
}
// restore the dialog modes
preferences.rulerUnits = gStartRulerUnits;
preferences.typeUnits = gStartTypeUnits;
displayDialogs = gStartDisplayDialogs;
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// 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;
}
// jpeg1 is the 50% size, jpeg2 is the 25% size, jpeg3 is thumbnail
// added:
function InitParams() {
// main params
var params = new Array();
params["version"] = gVersion;
params["source"] = "";
params["jpeg1"] = true;
params["jpeg2"] = true;
params["jpeg3"] = true;
params["q1"] = 8;
params["q2"] = 6;
params["q3"] = 5;
params["s"] = 225;
params["visibleCopyrightText"] = "";
params["hiddenCopyrightText"] = "";
params["photographerName"] = "";
return params;
}
// the main class
function ImageProcessor() {
gParams = InitParams();
// define the main dialog resource
// [left, top, right, bottom]
var dialogResource = "dialog { text: 'Image Processor', bounds:[100, 100, 480, 480], "
dialogResource += " sourceSt: StaticText { text:'Source:', bounds:[10, 10, 300, 30] }, "
dialogResource += " sourceEt: EditText { text:'', bounds:[10, 30, 200, 50], properties: { multiline:false } }, "
dialogResource += " sourceBtn: Button { text:'Browse...', bounds:[210, 30, 290, 50] }, "
dialogResource += " runBtn: Button { text:'Run', bounds:[310, 20, 370, 40] }, "
dialogResource += " cancelBtn: Button { text:'Cancel', bounds:[310, 50, 370, 70] }, "
dialogResource += " fileTypePnl: Panel { text: 'File Type:', bounds:[10, 80, 340, 185], "
dialogResource += " jpeg1Cb: Checkbox { text:'JPEG 50%', bounds:[10, 15, 120, 35], value:true }, "
dialogResource += " quality1St: StaticText { text:'Quality:', bounds:[130, 17, 180, 35] }, "
dialogResource += " quality1Et: EditText { text:'5', bounds:[180, 15, 210, 33] }, "
dialogResource += " jpeg2Cb: Checkbox { text:'JPEG 25%', bounds:[10, 40, 120, 60], value:true }, "
dialogResource += " quality2St: StaticText { text:'Quality:', bounds:[130, 42, 180, 60] }, "
dialogResource += " quality2Et: EditText { text:'5', bounds:[180, 40, 210, 58] }, "
dialogResource += " jpeg3Cb: Checkbox { text:'JPEG 225 px.', bounds:[10, 65, 120, 85], value:true }, "
dialogResource += " quality3St: StaticText { text:'Quality:', bounds:[130, 67, 180, 85] }, "
dialogResource += " quality3Et: EditText { text:'5', bounds:[180, 65, 210, 83] }, "
dialogResource += " sizeSt: StaticText { text:'Size:', bounds:[220, 67, 250, 85] }, "
dialogResource += " sizeEt: EditText { text:'225', bounds:[260, 65, 290, 83] }, "
dialogResource += " }, "
dialogResource += " copyrightInfoHiddenSt: StaticText { text:'Hidden Copyright Info:', bounds:[10, 195, 200, 210] }, "
dialogResource += " copyrightInfoHiddenEt: EditText { text:'', bounds:[10, 215, 340, 235] }, "
dialogResource += " copyrightInfoVisibleSt: StaticText { text:'Visible Copyright Info:', bounds:[10, 240, 200, 255] }, "
dialogResource += " copyrightInfoVisibleEt: EditText { text:'', bounds:[10, 260, 340, 280] }, "
dialogResource += " photographerSt: StaticText { text:'Photographer Name:', bounds:[10, 285, 200, 300] }, "
dialogResource += " photographerEt: EditText { text:'', bounds:[10, 305, 340, 325] } "
dialogResource += " }, "
dialogResource += " } "
dialogResource += "}";
// create the main dialog window, this holds all our data
this.mainDialog = new Window( dialogResource );
// routine for running the dialog and it's interactions
this.RunDialog = function () {
this.mainDialog.text = gScriptName;
this.mainDialog.cancelBtn.onClick = function() { this.parent.close( false ); }
this.mainDialog.sourceBtn.onClick = function() {
var selFolder = Folder.selectDialog( "Pick a source folder", this.parent.sourceLongText );
if ( selFolder != null ) {
this.parent.sourceLongText = selFolder.fsName.toString()
this.parent.sourceEt.text = CreateShortFileName( this.parent.sourceLongText );
}
}
this.mainDialog.fileTypePnl.jpeg1Cb.onClick = function() {
this.parent.parent.fileTypePnl.quality1St.enabled = this.value;
this.parent.parent.fileTypePnl.quality1Et.enabled = this.value;
}
this.mainDialog.fileTypePnl.jpeg2Cb.onClick = function() {
this.parent.parent.fileTypePnl.quality2St.enabled = this.value;
this.parent.parent.fileTypePnl.quality2Et.enabled = this.value;
}
this.mainDialog.fileTypePnl.jpeg3Cb.onClick = function() {
this.parent.parent.fileTypePnl.quality3St.enabled = this.value;
this.parent.parent.fileTypePnl.quality3Et.enabled = this.value;
this.parent.parent.fileTypePnl.sizeEt.enabled = this.value;
}
this.mainDialog.runBtn.onClick = function () {
// check if the settings are proper
var testFolder = null;
if ( this.parent.sourceEt.text != CreateShortFileName( this.parent.sourceLongText ) ) {
this.parent.sourceLongText = this.parent.sourceEt.text;
}
if ( this.parent.sourceLongText.length > 0 && this.parent.sourceLongText[0] != '.' ) {
testFolder = new Folder( this.parent.sourceLongText );
if ( !testFolder.exists ) {
alert( "Please specify a source folder." );
return;
}
} else {
alert( "Please specify a source folder." );
return;
}
if ( this.parent.fileTypePnl.jpeg1Cb.value == true ) {
var q = Number( this.parent.fileTypePnl.quality1Et.text );
if ( q < 0 || q > 12 ) {
alert( "JPEG Quality must be between 0 and 12." );
return;
}
}
if ( this.parent.fileTypePnl.jpeg2Cb.value == true ) {
var q = Number( this.parent.fileTypePnl.quality2Et.text );
if ( q < 0 || q > 12 ) {
alert( "JPEG Quality must be between 0 and 12." );
return;
}
}
if ( this.parent.fileTypePnl.jpeg3Cb.value == true ) {
var q = Number( this.parent.fileTypePnl.quality3Et.text );
if ( q < 0 || q > 12 ) {
alert( "JPEG Quality must be between 0 and 12." );
return;
}
}
// make sure they have at least one file format specified for output
var outputCount = 0;
if ( this.parent.fileTypePnl.jpeg1Cb.value == true ) {
outputCount++;
}
if ( this.parent.fileTypePnl.jpeg2Cb.value == true ) {
outputCount++;
}
if ( this.parent.fileTypePnl.jpeg3Cb.value == true ) {
outputCount++;
}
if ( outputCount == 0 ) {
alert( "You must save to at least one file type." );
return;
}
// transfer the params out of the dialog
GetParamsFromDialog( this.parent, gParams )
// success
this.parent.close( true );
}
InitDialog( this.mainDialog, gParams );
ForceDialogUpdate( this.mainDialog );
// this.mainDialog.center();
return this.mainDialog.show();
}
// if I get here then the dialog params are ok and it is time
// to do what they want
this.Execute = function() {
var cameraRawParams = new Object();
cameraRawParams.desc = undefined;
cameraRawParams.useDescriptor = false;
cameraRawParams.fileName = gParams["source"] + "/x";
if ( gParams["open"] == true ) {
cameraRawParams.useDescriptor = true;
cameraRawParams.fileName = this.GetFirstFile( gParams["source"] );
if (debug_alerts) {
alert("after GetFirstFile, thinking about working on " + cameraRawParams.fileName);
}
if ( ! IsFileOneOfThese( cameraRawParams.fileName, gFilesToSkip ) ) {
if (debug_alerts) {
alert("after GetFirstFile, trying to open, as a raw, " + cameraRawParams.fileName);
}
if ( this.OpenCameraRaw( cameraRawParams ) ) {
this.AdjustFile( cameraRawParams );
this.SaveFile( cameraRawParams.fileName, gParams["source"] );
activeDocument.close( SaveOptions.DONOTSAVECHANGES );
} else {
return;
}
} else {
alert( "This is not a camera raw file according to my list of extensions, " + cameraRawParams.fileName );
return;
}
}
this.OpenAdjustSaveTheRest( cameraRawParams );
}
// the heart of the script is this routine and Execute
// loop through all the files and save accordingly
this.OpenAdjustSaveTheRest = function( inCameraRawParams ) {
var firstFileAsLowerCaseString = "";
if ( inCameraRawParams.fileName != undefined ) {
firstFileAsLowerCaseString = inCameraRawParams.fileName.toString().toLowerCase();
}
var inputFiles;
if ( gParams["flagged"] == true ) {
inputFiles = GetFilesFromFileBrowser( true, false );
} else if ( gParams["selected"] == true ) {
inputFiles = GetFilesFromFileBrowser( false, true );
} else {
var workingFolder = File( inCameraRawParams.fileName ).parent;
inputFiles = Folder( workingFolder ).getFiles();
}
for (var i = 0; i < inputFiles.length; i++) {
var thisFileAsLowerCaseString = inputFiles[i].toString().toLowerCase();
if (inputFiles[i] instanceof File && inputFiles[i].hidden == false && firstFileAsLowerCaseString != thisFileAsLowerCaseString ) {
inCameraRawParams.fileName = inputFiles[i].toString();
if (debug_alerts) {
alert("thinking about working on " + inCameraRawParams.fileName);
}
if ( ! IsFileOneOfThese( inCameraRawParams.fileName, gFilesToSkip ) ) {
if (debug_alerts) {
alert("opening with OpenCameraRaw " + inCameraRawParams.fileName);
}
this.OpenCameraRaw( inCameraRawParams, DialogModes.NO );
this.AdjustFile( inCameraRawParams );
this.SaveFile( inCameraRawParams.fileName, gParams["source"] );
activeDocument.close( SaveOptions.DONOTSAVECHANGES );
}
}
}
}
// using the dialog adjust the active document
this.AdjustFile = function ( inOutCameraRawParams ) {
var docRef = activeDocument;
if ( gParams["hiddenCopyrightText"] != "" ) {
docRef.info.copyrightNotice = gParams["hiddenCopyrightText"];
docRef.info.copyrighted = CopyrightedType.COPYRIGHTEDWORK;
}
if ( gParams["photographerName"] != "" ) {
docRef.info.author = gParams["photographerName"];
docRef.info.ownerUrl = "http://philip.greenspun.com";
}
}
// I can save in three formats, JPEG, JPEG, JPEG
this.SaveFile = function ( inFileName, inFolderLocation ) {
var lastDot = inFileName.lastIndexOf( "." );
var fileNameNoPath = inFileName.substr( 0, lastDot ); // nameExtensionArray[0].split("/");
var lastSlash = fileNameNoPath.lastIndexOf( "/" );
fileNameNoPath = fileNameNoPath.substr( lastSlash + 1, fileNameNoPath.length );
if ( ! Folder( inFolderLocation + "/JPEG/" ).exists ) {
if ( ! Folder( inFolderLocation + "/JPEG/" ).create() ) {
throw( "Could not create output folder " + inFolderLocation + "/JPEG/" );
}
}
activeDocument.flatten();
activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;
RemoveAlphaChannels();
if ( gParams["jpeg1"] == true ) {
var subFolderText = inFolderLocation;
var historyState = activeDocument.activeHistoryState;
FitImage( 1536, 1536 );
activeDocument.activeLayer.applyUnSharpMask(100,2.0,2);
AdjustBigForCopyright();
var uniqueFileName = subFolderText + "/JPEG/" + fileNameNoPath + ".4.jpg";
SaveAsJPEG( uniqueFileName, gParams["q1"], true );
activeDocument.activeHistoryState = historyState;
}
if ( gParams["jpeg2"] == true ) {
var subFolderText = inFolderLocation;
var historyState = activeDocument.activeHistoryState;
FitImage( 768, 768 );
activeDocument.activeLayer.applyUnSharpMask(100,1.0,2);
AdjustMediumForCopyright();
var uniqueFileName = subFolderText + "/JPEG/" + fileNameNoPath + ".3.jpg";
SaveAsJPEG( uniqueFileName, gParams["q2"], true );
activeDocument.activeHistoryState = historyState;
}
// this is a thumbnail so we don't AdjustforCopyright
if ( gParams["jpeg3"] == true ) {
var subFolderText = inFolderLocation;
var historyState = activeDocument.activeHistoryState;
FitImage( gParams["s"], gParams["s"] );
// let's sharpen now, after resizing, just before jpegging
activeDocument.activeLayer.applyUnSharpMask(100,0.25,2);
AddThumbnailBorders();
var uniqueFileName = subFolderText + "/JPEG/" + fileNameNoPath + ".1.jpg";
// no embed color profile
SaveAsJPEG( uniqueFileName, gParams["q3"], false );
activeDocument.activeHistoryState = historyState;
}
// let's also make a .2.jpg size (about 256x384)
var subFolderText = inFolderLocation;
var historyState = activeDocument.activeHistoryState;
FitImage( 384, 384 );
// let's sharpen now, after resizing, just before jpegging
activeDocument.activeLayer.applyUnSharpMask(100,0.5,2);
AddThumbnailBorders();
var uniqueFileName = subFolderText + "/JPEG/" + fileNameNoPath + ".2.jpg";
// no embed color profile
SaveAsJPEG( uniqueFileName, gParams["q3"], false );
activeDocument.activeHistoryState = historyState;
// layer upon layer of crud... added October 2006 by philg@mit.edu
// to make a JPEG the same size as the original
var subFolderText = inFolderLocation;
var historyState = activeDocument.activeHistoryState;
// no resize, just sharpen
activeDocument.activeLayer.applyUnSharpMask(100,2.0,2);
// add big borders and text, same as the .5.jpg
AdjustBigForCopyright();
var uniqueFileName = subFolderText + "/JPEG/" + fileNameNoPath + ".jpg";
// this is for printing, so we make it high quality
SaveAsJPEG( uniqueFileName, 9, true );
activeDocument.activeHistoryState = historyState;
}
// open a camera raw file returning the camera raw action desc
this.OpenCameraRaw = function( inOutCameraRawParams, inDialogMode ) {
var keyNull = charIDToTypeID( 'null' );
var keyAs = charIDToTypeID( 'As ' );
var adobeCameraRawID = stringIDToTypeID( "Adobe Camera Raw" );
var desc = new ActionDescriptor();
desc.putPath( keyNull, File( inOutCameraRawParams.fileName ) );
if ( inOutCameraRawParams.desc != undefined && inOutCameraRawParams.useDescriptor == true &&
IsFileOneOfThese( inOutCameraRawParams.fileName, gFilesForCameraRaw ) ) {
desc.putObject( keyAs, adobeCameraRawID, inOutCameraRawParams.desc );
}
if ( inDialogMode == undefined ) {
inDialogMode = DialogModes.ALL;
}
var returnDesc = executeAction( charIDToTypeID( 'Opn ' ), desc, inDialogMode );
if ( returnDesc.hasKey( keyAs ) ) {
inOutCameraRawParams.desc = returnDesc.getObjectValue( keyAs, adobeCameraRawID );
if ( returnDesc.hasKey( keyNull ) ) {
inOutCameraRawParams.fileName = returnDesc.getPath( keyNull ).toString();
return true;
}
}
return false;
}
// given a folder return the first valid file in that folder
this.GetFirstFile = function ( inFolder ) {
if ( inFolder.length > 0 && inFolder[0] != '.' ) {
var fileList = Folder( inFolder ).getFiles();
for ( var i = 0; i < fileList.length; i++) {
if ( fileList[i] instanceof File && fileList[i].hidden == false && ! IsFileOneOfThese( fileList[i], gFilesToSkip ) ) {
return fileList[i].toString();
}
}
}
return "";
}
}
function SaveAsJPEG( inFileName, inQuality, inEmbedICC ) {
var jpegOptions = new JPEGSaveOptions();
jpegOptions.quality = inQuality;
jpegOptions.embedColorProfile = inEmbedICC;
activeDocument.saveAs( File( inFileName ), jpegOptions );
}
function SaveAsPSD( inFileName, inMaximizeCompatibility, inEmbedICC ) {
var psdSaveOptions = new PhotoshopSaveOptions();
psdSaveOptions.embedColorProfile = inEmbedICC;
psdSaveOptions.maximizeCompatibility = inMaximizeCompatibility;
activeDocument.saveAs( File( inFileName ), psdSaveOptions );
}
function SaveAsTIFF( inFileName, inEmbedICC, inLZW ) {
var tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = inEmbedICC;
if ( inLZW ) {
tiffSaveOptions.imageCompression = TIFFEncoding.TIFFLZW;
} else {
tiffSaveOptions.imageCompression = TIFFEncoding.NONE;
}
activeDocument.saveAs( File( inFileName ), tiffSaveOptions );
}
// use the fit image automation plug-in to do this work for me
function FitImage( inWidth, inHeight ) {
if ( inWidth == undefined || inHeight == undefined ) {
alert("Width and Height must be defined to use FitImage function!");
return;
}
var desc = new ActionDescriptor();
var unitPixels = charIDToTypeID( '#Pxl' );
desc.putUnitDouble( charIDToTypeID( 'Wdth' ), unitPixels, inWidth );
desc.putUnitDouble( charIDToTypeID( 'Hght' ), unitPixels, inHeight );
var runtimeEventID = stringIDToTypeID( "3caa3434-cb67-11d1-bc43-0060b0a13dc4" );
executeAction( runtimeEventID, desc, DialogModes.NO );
}
// get all the files in the file browser that are selected or flagged
function GetFilesFromFileBrowser( flagged, selected ) {
var fileArray = new Array();
var ffIndex = 0;
var ref = new ActionReference();
var fileBrowserStrID = stringIDToTypeID( "fileBrowser" )
// ask for all keys and then do a haskey ref.putProperty( charIDToTypeID( 'Prpr' ), fileBrowserStrID );
ref.putEnumerated( charIDToTypeID( 'capp' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
var desc = executeActionGet( ref );
if ( desc.count > 0 && desc.hasKey( fileBrowserStrID ) ) {
var fbDesc = desc.getObjectValue( fileBrowserStrID );
var keyFilesList = charIDToTypeID( 'flst' );
if ( fbDesc.count > 0 && fbDesc.hasKey( keyFilesList ) ) {
var fileList = fbDesc.getList( keyFilesList );
var flaggedID = stringIDToTypeID( "flagged" );
var selectedID = charIDToTypeID( 'fsel' );
var keyPath = charIDToTypeID( 'Path' );
for ( var i = 0; i < fileList.count; i++ ) {
var fileDesc = fileList.getObjectValue( i );
if ( fileDesc.count > 0 && fileDesc.hasKey( keyPath )) {
if ( flagged == true && fileDesc.hasKey( flaggedID ) && fileDesc.getBoolean( flaggedID )) {
var fileOrFolder = fileDesc.getPath( keyPath );
if ( fileOrFolder instanceof File ) {
fileArray[ffIndex++] = fileOrFolder;
}
}
if ( selected == true && fileDesc.hasKey( selectedID ) && fileDesc.getBoolean( selectedID )) {
var fileOrFolder = fileDesc.getPath( keyPath );
if ( fileOrFolder instanceof File ) {
fileArray[ffIndex++] = fileOrFolder;
}
}
}
}
}
}
return fileArray;
}
// a very crude xml parser, this reads the "Tag" of the Data
function ReadHeader( inFile ) {
var returnValue = "";
if ( ! inFile.eof ) {
var c = "";
while ( c != "<" && ! inFile.eof ) {
c = inFile.read( 1 );
}
while ( c != ">" && ! inFile.eof ) {
c = inFile.read( 1 );
if ( c != ">" ) {
returnValue += c;
}
}
} else {
returnValue = "end of file";
}
return returnValue;
}
// very crude xml parser, this reads the "Data" of the Data
function ReadData( inFile ) {
var returnValue = "";
if ( ! inFile.eof ) {
var c = "";
while ( c != "<" && ! inFile.eof ) {
c = inFile.read( 1 );
if ( c != "<" ) {
returnValue += c;
}
}
inFile.seek( -1, 1 );
}
return returnValue;
}
function CheckVersion() {
var numberArray = version.split(".");
if ( numberArray[0] < 8 ) {
alert( "You must use Photoshop CS or later to run this script!" );
throw( "You must use Photoshop CS or later to run this script!" );
}
}
function CreateUniqueFileName( inFolder, inFileName, inExtension ) {
var uniqueFileName = inFolder + inFileName + inExtension;
var fileNumber = 1;
while ( File( uniqueFileName ).exists ) {
uniqueFileName = inFolder + inFileName + "_" + fileNumber + inExtension;
fileNumber++;
}
return uniqueFileName;
}
function CreateShortFileName( inFileName ) {
if ( inFileName.length > gShortFileNameLength ) {
return "..." + inFileName.substr( inFileName.length - gShortFileNameLength + 3, gShortFileNameLength - 3 );
}
return inFileName;
}
function IsWindowsOS() {
if ( $.os.search(/windows/i) != -1 ) {
return true;
} else {
return false;
}
}
function RemoveAlphaChannels() {
var channels = activeDocument.channels;
var channelCount = channels.length - 1;
while ( channels[channelCount].kind != ChannelType.COMPONENT ) {
channels[channelCount].remove();
channelCount--;
}
}
function ConvertTosRGBProfile() {
var id136 = stringIDToTypeID( "convertToProfile" );
var desc31 = new ActionDescriptor();
var id137 = charIDToTypeID( "null" );
var ref6 = new ActionReference();
var id138 = charIDToTypeID( "Dcmn" );
var id139 = charIDToTypeID( "Ordn" );
var id140 = charIDToTypeID( "Trgt" );
ref6.putEnumerated( id138, id139, id140 );
desc31.putReference( id137, ref6 );
var id141 = charIDToTypeID( "T " );
desc31.putString( id141, "sRGB IEC61966-2.1" );
var id142 = charIDToTypeID( "Inte" );
var id143 = charIDToTypeID( "Inte" );
var id144 = charIDToTypeID( "Clrm" );
desc31.putEnumerated( id142, id143, id144 );
var id145 = charIDToTypeID( "MpBl" );
desc31.putBoolean( id145, true );
var id146 = charIDToTypeID( "Dthr" );
desc31.putBoolean( id146, true );
executeAction( id136, desc31, DialogModes.NO );
}
// load my params from the xml file on disk if it exists
// gParams["myoptionname"] = myoptionvalue
// I wrote a very simple xml parser, I'm sure it needs work
function LoadParamsFromDisk ( loadFile, params ) {
// var params = new Array();
if ( loadFile.exists ) {
loadFile.open( "r" );
var projectSpace = ReadHeader( loadFile );
if ( projectSpace == GetScriptNameForXML() ) {
while ( ! loadFile.eof ) {
var starter = ReadHeader( loadFile );
var data = ReadData( loadFile );
var ender = ReadHeader( loadFile );
if ( ( "/" + starter ) == ender ) {
params[starter] = data;
}
// force boolean values to boolean types
if ( data == "true" || data == "false" ) {
params[starter] = data == "true";
}
}
}
loadFile.close();
if ( params["version"] != gVersion ) {
// do something here to fix version conflicts
// this should do it
params["version"] = gVersion;
}
}
}
// save out my params, this is much easier
function SaveParamsToDisk ( saveFile, params ) {
saveFile.encoding = "UTF8";
saveFile.open( "w", "TEXT", "????" );
// unicode signature, this is UTF16 but will convert to UTF8 "EF BB BF"
saveFile.write("\uFEFF");
var scriptNameForXML = GetScriptNameForXML();
saveFile.writeln( "<" + scriptNameForXML + ">" );
for ( var p in params ) {
saveFile.writeln( "\t<" + p + ">" + params[p] + "" + p + ">" );
}
saveFile.writeln( "" + scriptNameForXML + ">" );
saveFile.close();
}
// you can't save certain characters in xml, strip them here
// this list is not complete
function GetScriptNameForXML () {
var scriptNameForXML = new String( gScriptName );
var charsToStrip = Array( " ", "'", "." );
for (var a = 0; a < charsToStrip.length; a++ ) {
var nameArray = scriptNameForXML.split( charsToStrip[a] );
scriptNameForXML = "";
for ( var b = 0; b < nameArray.length; b++ ) {
scriptNameForXML += nameArray[b];
}
}
return scriptNameForXML;
}
// transfer from the default settings or settings I read off disk to the dialog widgets
function InitDialog( dialog, params ) {
dialog.sourceEt.text = CreateShortFileName( params["source"] );
dialog.sourceLongText = params["source"];
dialog.lastSource = params["source"];
dialog.fileTypePnl.jpeg1Cb.value = params["jpeg1"];
dialog.fileTypePnl.jpeg2Cb.value = params["jpeg2"];
dialog.fileTypePnl.jpeg3Cb.value = params["jpeg3"];
dialog.fileTypePnl.quality1Et.text = params["q1"];
dialog.fileTypePnl.quality2Et.text = params["q2"];
dialog.fileTypePnl.quality3Et.text = params["q3"];
dialog.fileTypePnl.sizeEt.text = params["s"];
dialog.copyrightInfoHiddenEt.text = params["hiddenCopyrightText"];
dialog.copyrightInfoVisibleEt.text = params["visibleCopyrightText"];
dialog.photographerEt.text = params["photographerName"];
}
// pretend like i clicked it to get the other items to respond to the current settings
function ForceDialogUpdate( dialog ) {
dialog.fileTypePnl.jpeg1Cb.onClick();
dialog.fileTypePnl.jpeg2Cb.onClick();
dialog.fileTypePnl.jpeg3Cb.onClick();
}
// transfer from the dialog widgets to my internal params
function GetParamsFromDialog( dialog, params ) {
if ( dialog.sourceEt.text != CreateShortFileName( dialog.sourceLongText ) )
params["source"] = dialog.sourceEt.text;
else
params["source"] = dialog.sourceLongText;
params["jpeg1"] = dialog.fileTypePnl.jpeg1Cb.value;
params["jpeg2"] = dialog.fileTypePnl.jpeg2Cb.value;
params["jpeg3"] = dialog.fileTypePnl.jpeg3Cb.value;
params["q1"] = dialog.fileTypePnl.quality1Et.text;
params["q2"] = dialog.fileTypePnl.quality2Et.text;
params["q3"] = dialog.fileTypePnl.quality3Et.text;
params["s"] = dialog.fileTypePnl.sizeEt.text;
params["hiddenCopyrightText"] = dialog.copyrightInfoHiddenEt.text;
params["visibleCopyrightText"] = dialog.copyrightInfoVisibleEt.text;
params["photographerName"] = dialog.photographerEt.text;
return params;
}
/////////////////////////////////////////////////////////////////////
// Function: MacXMLFilter
// Input: f, file or folder to check
// Return: true or false, true if file or folder is to be displayed
/////////////////////////////////////////////////////////////////////
function MacXMLFilter( f )
{
var xmlExtension = "*.xml";
var lCaseName = f.name;
lCaseName.toLowerCase();
if ( lCaseName.indexOf( xmlExtension ) == f.name.length - xmlExtension.length )
return true;
else if ( f.type == 'TEXT' )
return true;
else if ( f instanceof Folder )
return true;
else
return false;
}
// figure out what I call my params file
function GetDefaultParamsFile() {
var paramsFolder = new Folder( path + "/Presets/" + gScriptName );
paramsFolder.create();
return ( new File( paramsFolder + "/" + gScriptName + ".xml" ) );
}
function AdjustBigForCopyright() {
CanvasSize( 35, 35 );
CanvasSizeHeightAnchorTop( 7 );
AddBigTextAtBottom();
}
function AdjustMediumForCopyright() {
CanvasSize( 20, 20 );
CanvasSizeHeightAnchorTop( 5 );
AddMediumTextAtBottom();
}
function AddThumbnailBorders () {
CanvasSize( 5, 5 );
}
function CanvasSize( width, height ) {
var id24 = charIDToTypeID( "CnvS" );
var desc5 = new ActionDescriptor();
var id25 = charIDToTypeID( "Rltv" );
desc5.putBoolean( id25, true );
var id26 = charIDToTypeID( "Wdth" );
var id27 = charIDToTypeID( "#Pxl" );
desc5.putUnitDouble( id26, id27, width );
var id28 = charIDToTypeID( "Hght" );
var id29 = charIDToTypeID( "#Pxl" );
desc5.putUnitDouble( id28, id29, height );
var id30 = charIDToTypeID( "Hrzn" );
var id31 = charIDToTypeID( "HrzL" );
var id32 = charIDToTypeID( "Cntr" );
desc5.putEnumerated( id30, id31, id32 );
var id33 = charIDToTypeID( "Vrtc" );
var id34 = charIDToTypeID( "VrtL" );
var id35 = charIDToTypeID( "Cntr" );
desc5.putEnumerated( id33, id34, id35 );
var id36 = stringIDToTypeID( "canvasExtensionColorType" );
var id37 = stringIDToTypeID( "canvasExtensionColorType" );
var id38 = charIDToTypeID( "Blck" );
desc5.putEnumerated( id36, id37, id38 );
executeAction( id24, desc5, DialogModes.NO );
}
function CanvasSizeHeightAnchorTop( height ) {
var id106 = charIDToTypeID( "CnvS" );
var desc22 = new ActionDescriptor();
var id107 = charIDToTypeID( "Rltv" );
desc22.putBoolean( id107, true );
var id108 = charIDToTypeID( "Hght" );
var id109 = charIDToTypeID( "#Pxl" );
desc22.putUnitDouble( id108, id109, height );
var id110 = charIDToTypeID( "Vrtc" );
var id111 = charIDToTypeID( "VrtL" );
var id112 = charIDToTypeID( "Top " );
desc22.putEnumerated( id110, id111, id112 );
var id113 = stringIDToTypeID( "canvasExtensionColorType" );
var id114 = stringIDToTypeID( "canvasExtensionColorType" );
var id115 = charIDToTypeID( "Blck" );
desc22.putEnumerated( id113, id114, id115 );
executeAction( id106, desc22, DialogModes.NO );
}
// functions that actually draw the text
// tried textLayer.textItem.height = 20; but got an error saying that this was only for "paragraph text"
function AddBigTextAtBottom() {
// foregroundColor.model = ColorModel.RGB;
foregroundColor.rgb.red = 255;
foregroundColor.rgb.green = 255;
foregroundColor.rgb.blue = 255;
var textLayer = activeDocument.artLayers.add();
textLayer.kind = LayerKind.TEXT;
textLayer.name = "Copyright Note";
textLayer.textItem.contents = gParams["visibleCopyrightText"];
textLayer.textItem.color = foregroundColor;
textLayer.textItem.font = "9x15";
textLayer.textItem.antiAliasMethod = AntiAlias.NONE;
stringwidth = textLayer.textItem.contents.length*9
textLayer.textItem.position = new Array( activeDocument.width - stringwidth - 20, activeDocument.height - 6 );
}
function AddMediumTextAtBottom() {
// foregroundColor.model = ColorModel.RGB;
foregroundColor.rgb.red = 255;
foregroundColor.rgb.green = 255;
foregroundColor.rgb.blue = 255;
var textLayer = activeDocument.artLayers.add();
textLayer.kind = LayerKind.TEXT;
textLayer.name = "Copyright Note";
textLayer.textItem.contents = gParams["visibleCopyrightText"];
stringwidth = textLayer.textItem.contents.length*6
textLayer.textItem.position = new Array( activeDocument.width - stringwidth - 10, activeDocument.height - 3 );
textLayer.textItem.color = foregroundColor;
textLayer.textItem.font = "6x13";
textLayer.textItem.antiAliasMethod = AntiAlias.NONE;
textLayer.textItem.kind = TextType.PARAGRAPHTEXT;
// font size is very odd, so says our Adobe guru
}
// JavaScript lore
// you need some sort of weird prefix character before the copyright symbol
/// or JavaScript complains about an unterminated string
// textLayer.name = "© 2004 http://philip.greenspun.com/copyright/";