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!
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
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
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.)
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.
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.
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