Here’s the code I use to try to save the current Photoshop document as a JPEG:
async function saveAsJPEG(quality = 6) {
try {
// Prompt the user to select a save location
const entry = await fs.getFileForSaving(“output.jpeg”);
if (!entry) {
console.error("No location selected for saving.");
return;
}
const outputFileToken = await fs.createSessionToken(entry);
// Use batchPlay to save the document as JPEG
const result = await app.batchPlay([
{
"_obj": "save",
"as": {
"_obj": "JPEG",
"options": {
"quality": quality,
"formatOptions": "optimized"
}
},
"in": {
"_path": outputFileToken,
"_kind": "local"
},
"documentID": app.activeDocument._id,
"copy": false,
"overwrite": true,
"_isCommand": true,
"_options": {
"dialogOptions": "dontDisplay"
}
}
], {
"synchronousExecution": true,
"modalBehavior": "fail"
});
if (result && result[0] && result[0].status === "OK") {
console.log("JPEG saved successfully");
} else {
console.error("Error while saving JPEG", result);
}
} catch (error) {
console.error("Error:", error);
}
}
When I run this, it instead saves as a .psd file. Why?
What’s weird is, it throws an error in the console log, but then ALSO circles back around to save as psd after that:
main.js:97 Error while saving JPEG
[{…}]
0:
1. as:
1. maximizeCompatibility: true
2. _obj: "photoshop35Format"
2. copy: true
3. documentID: 318
4. in:
1. _kind: "local"
2. _path: "C:\\Users\\anton\\Downloads\\TEST OUTPUT FOLDER\\output.psd"
5. lowerCase: true
6. saveStage:
1. _enum: "saveStageType"
2. _value: "saveSucceeded"
length: 1
sttk3
August 15, 2023, 1:37am
3
You need to specify copy: true
when saving JPEGs
Use of the jpg
extension instead of jpeg
, which is automatically converted to jpg
by Photoshop
If you use batchPlay, must provide exactly the properties and steps required by Photoshop. Probably use extendedQuality
instead of quality
, and two actions, saveBegin
and saveSucceeded
, need to be triggered
JPEG export can be replaced by Document.saveAs.jpg
const { localFileSystem } = require('uxp').storage ;
const photoshop = require('photoshop') ;
const { app, core } = photoshop ;
const saveAsJPEG = async (jpgQuality = 6) => {
// Prompt the user to select a save location
const entry = await localFileSystem.getFileForSaving('output.jpg') ;
if(!entry) {
console.error('No location selected for saving.') ;
return ;
}
const doc = app.activeDocument ;
if(!doc) {
console.error('There is no target document.') ;
return ;
}
await doc.saveAs.jpg(entry, {quality: jpgQuality}, true) ;
}
const main = async () => {
try {
await core.executeAsModal(
async (control) => {
await saveAsJPEG(7) ;
},
{
'commandName': 'Save as JPEG',
'interactive': true
}
) ;
} catch(e) {
await app.showAlert(e) ;
}
} ;
Interesting. I ended up writing it like this to make it work:
async function saveDocumentAsJPEGToFolder(filename, quality, folder) {
try {
// Prompt the user to select a folder only once
const entry = await folder.createFile(`${app.activeDocument.title}_${filename.name}.jpeg`, { overwrite: true });
const outputFileToken = await fs.createSessionToken(entry);
// Use batchPlay to save the document as JPEG
const result = await app.batchPlay([
{
"_obj": "save",
"as": {
"_obj": "JPEG",
"options": {
"quality": quality,
"formatOptions": "optimized",
"matte": {
"_enum": "matteColor",
"_value": "none"
}
}
},
"in": {
"_path": outputFileToken,
"_kind": "local"
},
"documentID": app.activeDocument._id,
"copy": true, // Make sure to save a copy to prevent overwriting the original
"overwrite": true,
"_isCommand": true,
"_options": {
"dialogOptions": "dontDisplay"
}
}
], {
"synchronousExecution": true,
"modalBehavior": "fail"
});
if (result && result[0] && result[0].status === "OK") {
console.log(`JPEG (${filename}.jpeg) saved successfully`);
} else {
console.error("Error while saving JPEG", result);
}
} catch (error) {
console.error("Error:", error);
}
}
copy: true → appears to be the key thing I was missing.
I’m also kind of surprised it lets this run without doing executeAsModal.
sttk3
August 15, 2023, 7:37am
5
It can certainly only export, but errors are occurring and quality is not being specified, correct?
You can make the batchPlay as simple as this:
await batchPlay(
[
{
_obj: "save",
as: {
_obj: "JPEG",
extendedQuality: 12,
matteColor: {
_enum: "matteColor",
_value: "none",
},
},
copy: true,
in: {
_kind: "local",
_path: outputFileToken,
},
lowerCase: true,
},
],
{}
);
1 Like
lowerCase: true → is that supposed to set the filename as lowercase? Because I noticed 1) it doesn’t do that, and 2) the save operation works fine without that line.
Yeah, I agree, it doesn’t work for me either. Could be a bug or something I am not aware of!
Just spitting, but I always assumed that lowercase
applied only to the extension - e.g. .JPEG
vs .jpeg
and was a hangover from the old days of operating system discrepancies.
I’m totally willing to be corrected on this!