Saving a PNG file with UXP?

Is there a simple way to save a .png file of the active document in UXP?

    const uxp = require('uxp');
    const lfs = uxp.storage.localFileSystem;
    const userFolder = lfs.getFolder();
    const file = userFolder.createFile("test.png");

My problem boils down to the code above.

I correctly get a dialog to select the folder, select eg. the desktop or c: drive, after that all I get is “createFile is not a function”.

Is getFolder failing for some reason or has something changed about createFile, like I’ve got the arguments list wrong? Any help would be greatly appreciated :slight_smile: :grinning_face_with_smiling_eyes:

You may need to use await when getting the userFolder. My guess is that is tries to run the createFile before the folder is defined. So this will also need to run from within an async function to use await.

Here is my save PNG which I have been using for all of my plugins with no issues. I patched this together from the various places in my plugins but should work in this order.

//My saveFolder is assigned as a global var earlier in the plugin
var saveFolder = await require("uxp").storage.localFileSystem.getFolder();

// Again, my variable here is global and assigned earlier. The value is changed during a batch loop for each file.
var saveFile = await saveFolder.createFile("fileName.png");  

// You need to assign a token before saving.  
const saveFileToken = await require("uxp").storage.localFileSystem.createSessionToken(saveFile);  

//To save the file
await savePNG(saveFileToken); 

/* 
The save function is batchPlay.  This is the only way I found to control the compression type. I could get the DOM to save as PNG. However, I could never get it to control the compressions type for PNG. That may be possible with the DOM but not documented... not sure.

For the save function, if running UXP AP1 version 1 then use "wait" for modalBehavior. This was a workaround for a PS bug that was causing issues with "fail".  

If running on UXP API version 2 then use "execute" for modalBahavior, or remove the options and use {} so the options go to default.
*/
async function savePNG(saveData){
    
const batchPlay = require("photoshop").action.batchPlay;

await batchPlay(
[
   {
      "_obj": "save",
      "as": {
         "_obj": "PNGFormat",
         "method": {
            "_enum": "PNGMethod",
            "_value": "quick"
         },
         "PNGInterlaceType": {
            "_enum": "PNGInterlaceType",
            "_value": "PNGInterlaceNone"
         },
         "PNGFilter": {
            "_enum": "PNGFilter",
            "_value": "PNGFilterAdaptive"
         },
         "compression": 6
      },
      "in": {
         "_path": saveData,
         "_kind": "local"
      },
      "saveStage": {
         "_enum": "saveStageType",
         "_value": "saveBegin"
      },
      "_isCommand": false,
      "_options": {
         "dialogOptions": "dontDisplay"
      }
   }
],{
   "synchronousExecution": false,
   "modalBehavior": "wait"
});    
    
    
}
1 Like

Thank you so much! I’ll try this tomorrow as soon as I’m on my dev machine.

I assume you’re right and it’s me trying to do this without async/wait is the problem, giving a null value to userFolder. I’m still new to UXP and I keep thinking in sync code terms.

Will confirm this as the answer as soon as I try the code. Huge thanks, a working snippet for reference is just what I needed :slight_smile:

asynchronous JS is a headache for sure. I’m not really sure what the benefits of it are in the UXP environment since all of the time-consuming operations need to use await anyway. It seems that anything that could save time by running asynchronous would be minimal in the grand scheme of things. But it is what it is. I’m pretty sure there are places where I use await when I don’t need to… when in doubt, await it out :slight_smile:

1 Like