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"
});    
    
    
}
2 Likes

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

Hi ddbell, thanks for your code example, it’s been very helpful.
I’m new to UXP and having some trouble figuring out how to save a file, getting confused with the methods and tokens, and your code is the first thing I came across that actually successfully saves a file to disk.
But I’m not able to make it save out a PNG, at the moment when I run your code directly, after prompting me for the folder, it prompts for file name, but the formats are limited to psd, psb, pdf, and tiff.
I can get the selection of other formats if I click “save a copy” in the prompt window, but I would really like to be able to modify the code to feed it a variable from the other part of my plugin script as the file path and name.

Also would you mind showing me how to assign a string to be the path? I can’t figure it out by reading the API reference document.

If you can help with that I’d hugely appreciate it.

Photoshop doesn’t give you the option to save a file as a particular format if the document doesn’t conform to the file specs - my guess would be that you’re not getting the option for .PNG because your file is layered/unflattened, in an unsupported mode (e.g. bitmap, 32bit, etc), or something along those lines. Off the top of my head I couldn’t tell you what the specs for a .PNG are. It may even just rely on if a file is unflattened or not - I can’t test it right now.
I’m thinking out loud here and could be wrong though!

3 Likes

Thank you sir, you are correct. I tested the same script with a flattened image and it spat out the png as expected. Now I think I just need to include the flatten and revert actions into my script and it will work.

1 Like

If you got a solution, it’s appropriate to mark answer as such for others to easier find solutions

1 Like