I am developing an Adobe extension, from within the extension I want to load a directory of images into separate layers within a document. I am completely impartial to how this is done - so if there is a better approach, please share it with me. My current working method involves using the open() method which opens a file in a new document, then duplicate the layer of the new document into the original document. An example of this can be seen below.
// open new document
var originalDoc = app.activeDocument;
var doc = open( new File( filePath ) );
// duplicate to original document
var layer = doc.activeLayer;
var newLayer = layer.duplicate(originalDoc, ElementPlacement.PLACEATBEGINNING);
// close new document
doc.close(SaveOptions.DONOTSAVECHANGES);
This method is extraordinarily slow, especially for large images. After doing some Googling I discovered that Photoshop has a built-in method for creating an image stack. This feature uses a .jsx script itself and it can be found on GitHub. Looking around online I found a few people trying to load a folders contents as layers, perfect. The main code I was interested in is below.
var folder = new Folder('~/Desktop/MyFolder');
function runLoadStack(folderPath) {
var loadLayersFromScript = true;
// #include 'Load Files into Stack.jsx'
var fList = folder.getFiles('*.png')
var aFlag = true;
loadLayers.intoStack(fList, aFlag);
}
runLoadStack(folder)
I immediately noticed the #include method of importing the stack methods, I can not find any official documentation for this (also not friendly with minification). Also, if the script is not placed with the same directory as Load Files into Stack.jsx it will throw the error Unable to open file: anonymous. And even after solving all of these issues when I run the .jsx script from within my extension using $.evalFile() I am having the same error as if the script is not in the correct directory: Unable to open file: anonymous. Error is being thrown on line 762 of an imported jsx.
Any help resolving the error I am experiencing or simply on how to load an array of image paths into layers (faster method) will be greatly appreciated!
Here is the code I am using within my extension:
var loadLayersFromScript = true;
var strPresets = localize("$$$/ApplicationPresetsFolder/Presets=Presets");
var strScripts = localize("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
var jsxFilePath = app.path + "/" + strPresets + "/" + strScripts + "/Load Files into Stack.jsx";
$.evalFile( new File( jsxFilePath ) );
loadLayers.intoStack( new Folder("/c/Users/Me/teststack").getFiles(), true );
Photoshop's inbuilt scripts has a script to do this here's the github link
https://github.com/ES-Collection/Photoshop-Scripts/blob/master/Import%20Folder%20As%20Layers.jsx
use this script inside your CEP extension
Related
I am following the instruction given here to integrate antlr4 with ace editor and I have trouble at the step var antlr4 = require('antlr4/index');. The author mentions that here we should use require for nodejs. However, ACE has another require that may cause problems. Thus he loaded another script for nodejs require and load antlr4/index with require in that script.
I tried that one, too. But it always cannot find the script. From the console of my browser, I can see the path it loads the script is:
localhost:4200/./antlr4/index.js and it fails to load it.
I am using Angular 7, and the structure of my project is as follows:
Also, when loading some local javascript file using importScripts, I always fails by giving the local path, however, giving URL from CDN will always work. But importScripts should support local file importing.
Where should I make changes and what else methods should I try?
Here are some of my code:
var ace_require = require;
window.require = undefined;
var Honey = { 'requirePath': ['..'] };
//importScript{"require.js"}
//the script can't be imported through importSctipt so I pasted the
//whole script file under...(not shown here)
var antlr4_require = window.require; // antlr4_require:antlr using nodejs require;
window.require = require = ace_require; // require:ace using its own require
var antlr4, LPMLNLexer, LPMLNParser;
try {
window.require = antlr4_require;
antlr4 = antlr4_require('antlr4/index');
//the browser stuck here reporting error...
} finally {
window.require = ace_require;
}
I'm creating a plugin I would like to be used for both Mac and Windows.
As the file trees are different, I would like to find a simpler way to source a file in a function contained in my /host/index.jsx file.
My file is located at /files/thisismyfile.psd
Currently I can only successfully source it by entering the full file tree from the main hard drive:
var fileRef = new File("/Library/Application Support/Adobe/CEP/extensions/com.my.panel/files/thisismyfile.psd");
I would much prefer to use something like:
var fileRef = new File("./files/thisismyfile.psd");
I've also tried testing having the file in each other folder and simply searching for:
var fileRef = new File("thisismyfile.psd");
With no luck! Any ideas?
Failing that, is it possible to code it so that it says:
"If this is mac, then search for the file here. If this is windows, then search for the file here."?
I ended up using this script to determine the location of the file depending on whether the system being used is mac or windows.
function isMacOS() {
return ($.os.toLowerCase().indexOf('mac') >= 0);
}
var fileRef = isMacOS()
? new File("/Library/Application Support/Adobe/CEP/extensions/my.panel/files/filename.psd")
: new File("C:\Program Files\Common Files\Adobe\CEP\extensions\my.panel\files\filename.psd");
var docRef = app.open(fileRef);
};
Within our web application we load a lot of content from package files (zipped packages containing html, js, css, images and so on.) The module loader (client side JS) processes the packages and makes the content available to the DOM using blob urls.
While this works very nice, it's sometimes tedious to find the right piece of JavaScript file for debugging.
IE: in chrome in the development console->sources all blob urls are listed under (no domain) and have random names such as:
blob:https://example.com/0613efd7-6977-4872-981f-519eea0bc911
In a normal production environment there are roughly 100 lines like this, so finding the right one might take some time.
I'd pretty much like to name the blob urls, or do something to make them easier to find for debugging purposes. This seems possible since WebPack is doing something like this, however i can't seem to find how. Is there anybody that can hint me in the right direction.
Ok, the way I would do it is have some global that keeps a track of the URL's, using a simple reverse map.
One problem of course with this is that references to a blob that no longer exists will be kept in memory, but if say you was only enabling this for debugging purposes this might not be a problem.
var namedblobs = {};
function addNamedBlob(name, uri) {
namedblobs[uri] = name;
}
function getNamedBlob(uri) {
return namedblobs[uri];
}
function createSomeBlob() {
//for testing just a random number would do
return Math.random().toString();
}
var blob = createSomeBlob();
addNamedBlob("test1", blob);
addNamedBlob("test2", createSomeBlob());
console.log(getNamedBlob(blob)); //should be test1
Finally i have found a solution that works to my liking. For our application we already used a serviceworker which has caching active. So i ended up writing the module files into the serviceworker cache whenever somebody has debug mode turned on.
Since the url portion of the resource files is static this way, all the nice browser features such as breakpoints are now useable again.
Below i've posted the relevant code of the serviceworker. The rest of the code is just plain serviceworker caching.
api.serveScript = function(module, script, content){
try{
content = atob(content);
} catch(err){}
return new Promise(function(resolve, reject){
var init = {
status: 200,
statusText: "OK",
headers: {'Content-Type': 'text/javascript'}
};
caches.open("modulecache-1").then(function(cache) {
console.log('[ServiceWorker] Caching ' + module + "/" + script);
cache.put("/R/" + module + "/script/" + script, new Response(content, init));
resolve("/R/" + module + "/script/" + script);
});
});
}
Thanks for your answers and help. I hope this solution is going to help some others too.
#Keith's option is probably the best one. (create a Map of your blobURIs and easy to read file names).
You could also do a dynamic router that will point some nice url to the blobURIs, but if you are open to do this, then just don't use blobURIs.
An other hackish workaround, really less cleaner than the Map, would be to append a fragment identifier to your blobURI blob:https://example.com/0613efd7-6977-4872-981f-519eea0bc911#script_name.js.
Beware, This should work for application/javascript Blobs or some other resource types, but not for documents (html/svg/...) where this fragment identifier has a special meaning.
var hello = new Blob(["alert('hello')"], {type:'application/javascript'});
var script = document.createElement('script');
script.src = URL.createObjectURL(hello) + '#hello.js';
document.head.appendChild(script);
console.log(script.src);
var css = new Blob(["body{background:red}"], {type:'text/css'});
var style = document.createElement('link');
style.href = URL.createObjectURL(css) + '#style.css';
style.rel = 'stylesheet';
document.head.appendChild(style);
console.log(style.href);
And as a fiddle for browsers which doesn't like null origined StackSnippet's iframes.
I have a Google Sheets file with an attached Script. The script does a number of things, one is it makes a clone of it self using makeCopy. This portion works. Now I want to be able to keep the same cloned Google file name and same Google file ID and just update the content which includes a Spreadsheet and the associated Google script.
if (!fileFound){
var file = masterSSFile.makeCopy(reportFileName, RepFolder);
} else {
oldFile.setContent(masterSSFile.getBlob());
}
When I use makeCopy with the same file name it creates a second file with the same name but with a different file ID.
The else portion fails because .setContent argument seems to just accept text. The result is the word "Blob" in the oldFile, everything else is gone.
I have other scripts that update the contents of a existing spreadsheet by overriding the contents of the various sheets, but I also want the associated script to also be included in the updated file keeping the same file ID.
I found this....
Overwrite an Image File with Google Apps Script
and tried using
var masterSpreadsheetID = SpreadsheetApp.getActiveSpreadsheet().getId();
var masterSpreadsheetFile = DriveApp.getFileById(masterSpreadsheetID);
var oldFileID = oldFile.getId();
var oldFileName = oldFile.getName();
var newBlob = masterSpreadsheetFile.getBlob();
var file = {
title: oldFileName,
mimeType: 'application/vnd.google-apps.spreadsheet'
};
var f = Drive.Files.update(file, oldFileID, newBlob);
I get error: "We're sorry, a server error occurred. Please wait a bit and try again. " on this line: "Drive.Files.update(file, oldFileID, newBlob);"
After reading this:
https://github.com/google/google-api-nodejs-client/issues/495
it looks like Drive.Files.update(), does not support bound scripts.
I am new to javascript and am trying to write a script which can copy a photoshop file from the local drive to a FTP server. The file is opened in photoshop and the script is run inside it.
I followed documentation(pdf) on page 165.
var file_path = app.activeDocument.fullName
var file = new file ("/d/project/test_file.psd");
var ftp = new FtpConnection("ftp://192.168.1.150/DATA/") ;
ftp.login("username", "password");
ftp.cd("project")
ftp.put(file,"test_file.psd") ;
ftp.close() ;
file.close() ;
I get an error as the following:
Error 22: file does not have a constructor.
Line: 2
-> var file = new file("/d/project/test_file.psd");
I am not able to understand the issue properly.
Assuming you are already loading the Web Access library (webaccesslib) as stated in previous pages of your documentation, please ensure you're respecting capitalization when calling class instances.
var file = new File("/d/project/test_file.psd");
Must have File with capital F. The error is saying there's no implementation of class file.