Read currently opened images

My plugin contains lut files (.cube) and I used fs.readfilesync for rendering previews in panel. How to integrate reading files with out
require(‘uxp’).storage.localFileSystem.getFileForOpening() ?
My goal is getting preview of currently opened image (also in .raw formats) like it is done in com.adobe.ccx.start extension

Hi Willa - welcome to the Creative Cloud developer ecosystem! I’m assuming you’re trying to circumvent the file picker part of the workflow, and open a file with a known path without any user interaction. Unfortunately, UXP does not allow third parties to open files by just providing a path and requires user input for any file when you used getFileForOpening().

Instead, if your file is in your data folder, you should be able to get a token for it using

const fs = require('uxp').storage.localFileSystem;
const df = await fs.getDataFolder();
const token = df.getEntry('filename.cube')

or plugin folder:

const fs = require('uxp').storage.localFileSystem;
const df = await fs.getPluginFolder();
const token = df.getEntry('filename.cube')

Here’s the corresponding documentation. As long as you’re within the data or plugin folder sandbox, you can access/open files in there without user interaction.

Hope this helps!

2 Likes

Hi, Amandah,

Yes, I definitli trying this hook.

Thanks for clarifying!

Hey Amandah! This helps heaps! Any idea how you could then pass the token object to a batch script?

I’m trying to run a Displacment filter but need to reference a displacement map .PSD saved in the plugin folder. Kinda like below. But I feel like my scripts are not getting the nativePath in time.

async function action1() {
    const fs = require('uxp').storage.localFileSystem;
    const df = await fs.getPluginFolder();
    const token = df.getEntry('Map1.psd');
    const map = await token.nativePath;
    let result;
    let command = [
        {
            "_obj": "displace",
            "horizontalScale": 50,
            "verticalScale": 50,
            "displacementMap": {
                "_enum": "displacementMap",
                "_value": "stretchToFit"
            },
            "undefinedArea": {
                "_enum": "undefinedArea",
                "_value": "repeatEdgePixels"
            },
            "displaceFile": {
                "_path": map,
                "_kind": "local"
            },
            "_isCommand": true,
            "_options": {
                "dialogOptions": "dontDisplay"
            }
        }
    ]
    app.showAlert(token);
    result = await psAction.batchPlay(command, {});
}
async function runModalFunction() {
    await require("photoshop").core.executeAsModal(action1, {"commandName": "Action Commands"});
}
await runModalFunction();

I think with BP you have to pass the token itself instead of map path. Eg. "_path": token. At least that’s what I saw somewhere here, but actually didn’t have to deal with this myself yet

1 Like

Yeh, think I did try that, I also saw a similar post here somewhere where they passed the token object, but couldn’t get it working :pensive:

Got to convert the token from getEntry to a session token using createSessionToken. That should get it working.

But you’ve got one other issue: getEntry is asynchronous. So you really need to do this:

const token = await df.getEntry("Map1.psd");

— otherwise you’re just getting the Promise<Entry> wrapper, which is not what you want in this case. nativePath does not exist on Promise, but it does exist on Entry.

Also, accessing nativePath is synchronous, and so you don’t need await token.nativePath – you can drop the await there. (It will do no harm to await, but it’s not doing anything useful either.)

1 Like

OMG thank you so much!

I’ve literally spent 4 days trying to figure this one out (when designers try and code ahahahah)

30min of trying to work it out but now I got it working it makes a lot of sense, with your direction.

For the purposes of others that might learn from this, full code below and my understanding of how it works.

Full Code

// Global constants
const app = require('photoshop').app;
const psAction = require("photoshop").action;
const fs = require('uxp').storage.localFileSystem; //Needed to access file storage

// UI Elements - button to trigger the run action
document.getElementById("runEffect").addEventListener("click", init);

// Main Functions
async function init() {
    // Other functions in here
    async function action1() {
        const df = await fs.getPluginFolder(); //Get DIR to local plugin folder
        const file = await df.getEntry("Map1.psd"); //Get file within plugin DIR via promise? async function
        const fileToken = await fs.createSessionToken(file); //Convert promise to a session token
        let result;
        let command = [ // Add your batchPlay json in here
         
            // Convert Later to Smart Object - needed for most filters and Displace otherwise it will ask you to do it anyways, so may as well do this for the user
            {
                "_obj": "newPlacedLayer"
            },
           
            // Displace batchPlay script
            {
                "_obj": "displace",
                "horizontalScale": 50,
                "verticalScale": 50,
                "displacementMap": {
                    "_enum": "displacementMap",
                    "_value": "stretchToFit"
                },
                "undefinedArea": {
                    "_enum": "undefinedArea",
                    "_value": "repeatEdgePixels"
                },
                "displaceFile": {
                    "_path": fileToken, //Use the fileToken variable here
                    "_kind": "local"
                },
                "_isCommand": true,
                "_options": {
                    "dialogOptions": "dontDisplay" // Don't show any dialogs to the user
                }
            }
        ]
        result = await psAction.batchPlay(command, {}); //Not sure, wait for stuff?

    }
    await require("photoshop").core.executeAsModal(action1, {"commandName": "Action Commands"}); // Run the batchPlay actions
}

You don’t need to explicitly wait for the execution of batchPlay if there’s no code following this line. (It’s async and Photoshop will continue finishing the operation no matter if you wait for it or not)
Right now you’re assigning it to result but don’t do anything with it. If you’d do something like
console.log(result) afterwards though, the await needs to be there.

1 Like

Amazing thanks for clarifying mate. Your right I’m not doing anything after it. So could just update that call to?

psAction.batchPlay(command, {});

Would that be correct?

If your script is finished at this point, yes.
You can also have batchplay execute synchronously by adding "synchronousExecution": true to the options (empty brackets at the end). I’ve read somewhere though, that batchPlay will be or has already been split into two separate functions, one being async, the other one sync.

1 Like

It’s in the docs, but as the docs aren’t versioned, so I have no idea with which combination of Ps-UXP-Manifest versions it works

2 Likes