Re: Photoshop 7.0 and Save For Web
Re: Photoshop 7.0 and Save For Web
- Subject: Re: Photoshop 7.0 and Save For Web
- From: Jesper Storm Bache <email@hidden>
- Date: Thu, 04 Nov 2004 12:01:49 -0800
Up front I apologize for posting JavaScript to an AppleScript list.
On Nov 3, 2004, at 1:15 PM, Steve Suranie wrote:
Is Save For Web scriptable?
Not directly (meaning that there is no intuitive AppleScript methods).
But you can use the ActionManager functionality from JavaScript.
I'm taking hi res tif/eps files, resize the image to 72 dpi and 300
pixels (width or height, depending on which is larger) and then need
to save them all to one folder as jpg. I was using the Save As option
but half the files were not viewable on Netscape 7.0, Firefox or
Explorer, on either platform. (Safari displayed all the files). It
seems like PS's JPEG feature is putting out a truncated file or
something like that and the majority of browsers can't read the files.
Anyway, doing a few manual Save For Web tests seemed to correct it but
I can't find anything on scripting that feature. I'm not locked into
PS, I also have Graphic Convertor but I haven't scripted that before
and I wasn't sure if you could resize the file in that program.
SaveAs produces larger images than "Save for Web", so I recommend using
"Save for Web".
Below is a JavaScript that does what you are talking about (as far as I
can see) - it is a modified version of one I used for scaling my
wedding images.
To use it do:
Copy everything between the lines and put it into a text file. Save
that text file as plain text (not RTF) and give it an extension of
".js".
Launch Photoshop and from the file menu fins the Scripts sub-menu. In
Photoshop 7.0 I think it is inside the Automate sub-menu. In Photoshop
CS it is directly visible in the file menu. Choose the "Browse..."
option and point to the ".js" file that you saved.
The script will ask you for the folder containing your images and a
destination folder. The destination folder must be empty.
I am pretty sure that the script works in version 7.0. If it does not,
try replacing the following lines:
options.requested_height = new UnitValue("300", "px");
options.requested_width = new UnitValue("300", "px");
with
options.requested_height = 300;
options.requested_width = 300;
Hope it works for you.
Jesper
//----------------------------------------
/**
Copyright: 2004 - Jesper Storm Bache (bache.com)
*/
/**
* This method recursively iterates through the contents of a folder.
* Each file is passed to the "handleFile" routine.
* Each folder is passed to the "handleFolder" routine.
* Both routines should have the signature:
* bool handleX(diskItem, userObject)
* If the handleX routine returns false the iteration is cancelled.
* Either or both of "handleFile" and "handleFolder" may be NULL.
*
* @param diskItem The disk object to iterate. If diskItem is a file,
then
* nothing is done.
* If diskItem is a folder then the procedure will iterate over
* all items inside that folder
* @param optionObject A piece of data that is passed to callbacks.
* The method relies on the following properties on the
optionObject:
* "fileActionList" and "folderActionList"
*/
function processFolder(diskItem, optionObject)
{
var doContinue = true;
if (diskItem instanceof Folder)
{
var diskItems = diskItem.getFiles("*");
var itemCount = diskItems.length;
// process all the found items
var index = 0;
while (index < itemCount && doContinue)
{
var anItem = diskItems[index];
// If the found item is an alias/shortcut then resolve to the
original
if (anItem.alias)
{
anItem = anItem.resolve();
}
// Skip non existing files. A non-existing file is an alias/shortcut
where
// we cannot find the original
if (anItem != null)
{
if (anItem instanceof File)
{
doContinue = actionInvoker(anItem, optionObject, "fileActionList");
}
else if (anItem instanceof Folder)
{
doContinue = actionInvoker(anItem, optionObject,
"folderActionList");
if (doContinue)
{
doContinue = processFolder(anItem, optionObject);
}
}
else
{
throw "Unknown disk item encountered in processFolder";
}
}
++index;
}
}
return doContinue;
}
/**
* This method handles calling action callbacks for a given disk item.
* The method continues until either all installed handlers have been
called, or until
* a handler returns false
* @param diskItem The item that should be processed by installed
action handlers
* @param optionObject Object containing processing options
* @param listPropName The name of the property on optionObject that
contains the
* options
*/
function actionInvoker(diskItem, optionObject, listPropName)
{
var doContinue = true;
var actionList = optionObject[listPropName];
if (null != actionList)
{
var handlerCount = actionList.length;
var index = 0;
while(index < handlerCount && doContinue)
{
actionFunction = actionList[index][0];
actionOptions = actionList[index][1];
doContinue = actionFunction(diskItem, actionOptions);
++index;
}
}
return doContinue;
}
/**
* This method opens the specified file
*/
function myOpenFile(fileItem, optionObject)
{
app.open(fileItem);
return true;
}
/**
* This method changes the mode of the active document to 8 bit RGB.
* Grayscale images are not converted to RGB.
*/
function myChangeMode(fileItem, optionObject)
{
if (app.activeDocument.mode != DocumentMode.RGB &&
app.activeDocument.mode != DocumentMode.GRAYSCALE)
{
app.activeDocument.changeMode(ChangeMode.RGB);
}
if (app.activeDocument.bitsPerChannel != BitsPerChannelType.EIGHT)
{
app.activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;
}
return true;
}
/**
* This method ensures that the active document has a well defined
color profile
* If the image does not have a color profile to begin with, we assume
"Generic RGB Profile".
* The image is then converted to the requested profile
*/
function myChangeProfile(fileItem, optionObject)
{
if (app.activeDocument.mode == DocumentMode.RGB)
{
if (app.activeDocument.colorProfileType == ColorProfile.NONE)
{
app.activeDocument.colorProfileName = "Generic RGB Profile";
}
if (optionObject.requestedProfile &&
app.activeDocument.colorProfileName != optionObject.requestedProfile)
{
app.activeDocument.convertProfile(optionObject.requestedProfile,
Intent.PERCEPTUAL);
}
}
return true;
}
/**
* This method scales the active document to fit with in a given frame
*/
function myScaleImage(fileItem, optionObject)
{
var height_factor = optionObject.requested_height /
app.activeDocument.height;
var width_factor = optionObject.requested_width /
app.activeDocument.width;
if (width_factor > height_factor)
{
app.activeDocument.resizeImage(null, optionObject.requested_height,
72.0);
}
else
{
app.activeDocument.resizeImage(optionObject.requested_width, null,
72.0);
}
optionObject.actual_width = app.activeDocument.width;
optionObject.actual_height = app.activeDocument.height;
return true;
}
/**
* This method saves the active document as jpg and then close it
*/
function mySaveFile(fileItem, optionObject)
{
var destPath = optionObject.destFolder + "/" + fileItem.name;
var destFile = new File(destPath);
var filePath = destFile.fsName;
if (filePath.match(/\.jpg$/) ||
filePath.match(/\.psd/))
{
filePath = filePath.substring(0, filePath.length - 4);
}
else if (filePath.match(/\.jpeg$/))
{
filePath = filePath.substring(0, filePath.length - 5);
}
if (optionObject.suffix)
{
filePath = filePath + optionObject.suffix;
}
filePath = filePath + ".jpg";
destFile = new File(filePath);
// Black magic to invoke the SaveForWeb mechanism. SFW creates the
smallest
// files that is why we do not use the save as JPG option
var id5 = charIDToTypeID( "Expr" );
var desc3 = new ActionDescriptor();
var id6 = charIDToTypeID( "Usng" );
var desc4 = new ActionDescriptor();
var id7 = charIDToTypeID( "Op " );
var id8 = charIDToTypeID( "SWOp" );
var id9 = charIDToTypeID( "OpSa" );
desc4.putEnumerated( id7, id8, id9 );
var id10 = charIDToTypeID( "Fmt " );
var id11 = charIDToTypeID( "IRFm" );
var id12 = charIDToTypeID( "JPEG" );
desc4.putEnumerated( id10, id11, id12 );
var id13 = charIDToTypeID( "Intr" );
desc4.putBoolean( id13, false );
var id14 = charIDToTypeID( "Qlty" );
desc4.putInteger( id14, 60 );
var id15 = charIDToTypeID( "QChS" );
desc4.putInteger( id15, 0 );
var id16 = charIDToTypeID( "QCUI" );
desc4.putInteger( id16, 0 );
var id17 = charIDToTypeID( "QChT" );
desc4.putBoolean( id17, false );
var id18 = charIDToTypeID( "QChV" );
desc4.putBoolean( id18, false );
var id19 = charIDToTypeID( "Optm" );
desc4.putBoolean( id19, true );
var id20 = charIDToTypeID( "Pass" );
desc4.putInteger( id20, 1 );
var id21 = charIDToTypeID( "blur" );
desc4.putDouble( id21, 0.000000 );
var id22 = charIDToTypeID( "EICC" );
desc4.putBoolean( id22, false );
var id23 = charIDToTypeID( "Mtt " );
desc4.putBoolean( id23, true );
var id24 = charIDToTypeID( "MttR" );
desc4.putInteger( id24, 255 );
var id25 = charIDToTypeID( "MttG" );
desc4.putInteger( id25, 255 );
var id26 = charIDToTypeID( "MttB" );
desc4.putInteger( id26, 255 );
var id27 = charIDToTypeID( "SHTM" );
desc4.putBoolean( id27, false );
var id28 = charIDToTypeID( "SImg" );
desc4.putBoolean( id28, true );
var id29 = charIDToTypeID( "SSSO" );
desc4.putBoolean( id29, false );
var id30 = charIDToTypeID( "SSLt" );
var list1 = new ActionList();
desc4.putList( id30, list1 );
var id31 = charIDToTypeID( "DIDr" );
desc4.putBoolean( id31, false );
var id32 = charIDToTypeID( "In " );
desc4.putPath( id32, destFile );
var id33 = stringIDToTypeID( "SaveForWeb" );
desc3.putObject( id6, id33, desc4 );
executeAction( id5, desc3, DialogModes.NO );
optionObject.filename = destFile.name;
return true;
}
/**
* This method closes the active document
*/
function myCloseNoSaveFile(fileItem, optionObject)
{
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
return true;
}
/*
===============================================================
M A I N
===============================================================
*/
app.preferences.rulerUnits = Units.PIXELS;
var rootFolder = Folder.selectDialog("Select folder with photos");
if (rootFolder == null)
{
throw 1;
}
var destFolder = Folder.selectDialog("Select output folder (it must be
empty)");
if (destFolder == null)
{
throw 2;
}
if ((destFolder.getFiles("*")).length > 0)
{
alert("Destination folder must be empty");
throw 3;
}
var imageInfoFile = new File(destFolder.path + "/imageinfo.txt");
// ---------------------------------------------------------------
// Setup the image conversion options
var fileActionList = new Array();
if(0)
{
fileActionList[fileActionList.length] = new Array(myStopSoon, new
Object);
}
fileActionList[fileActionList.length] = new Array(myOpenFile, null);
var info_options = new Object;
// setup the color space conversion stage
{
var options = new Object;
options.requestedProfile = "sRGB Profile";
fileActionList[fileActionList.length] = new Array(myChangeMode,
options);
}
// setup the color space profile stage
{
var options = new Object;
fileActionList[fileActionList.length] = new Array(myChangeProfile,
options);
}
// Setup the resize stage
{
var options = new Object;
options.requested_height = new UnitValue("300", "px");
options.requested_width = new UnitValue("300", "px");
fileActionList[fileActionList.length] = new Array(myScaleImage,
options);
// store the options object in the info options as well, so we can get
// informationn about the resize
info_options.largeScaleOptions = options;
}
// Setup saving the image stage
{
var options = new Object;
options.destFolder = destFolder;
options.suffix = "";
fileActionList[fileActionList.length] = new Array(mySaveFile, options);
// store the options object in the info options as well, so we can get
// informationn about the small name
info_options.smallFileNameOptions = options;
}
// Setup the close stage
{
var options = new Object;
fileActionList[fileActionList.length] = new Array(myCloseNoSaveFile,
options);
}
var optionObject = new Object;
optionObject.fileActionList = fileActionList;
var result = processFolder(rootFolder, optionObject);
imageInfoFile.close();
//----------------------------------------
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Applescript-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden