Skip to content

Instantly share code, notes, and snippets.

@sttk3
Created January 14, 2025 07:36
Show Gist options
  • Save sttk3/dc6906d314f9ab8212e8be5b52348d5d to your computer and use it in GitHub Desktop.
Save sttk3/dc6906d314f9ab8212e8be5b52348d5d to your computer and use it in GitHub Desktop.
Illustrator script to execute ExtendScript saved in cloud document. Proof-of-concept
/**
* @file Illustrator script to execute ExtendScript saved in cloud document. Proof-of-concept.
* Assuming json2.jsx is in the same folder as this script
* @version 1.0.0
* @author sttk3.com
* @copyright © 2025 sttk3.com
*/
//@target 'illustrator'
//@include 'json2.jsx'
$.localize = true ;
(function() {
// exit if cloud document is disabled
if(!cloudAvailable()) {
var errorMessage = {
ja: 'このスクリプトはIllustrator 2020かそれ以降が必要です。',
en: 'This script requires Illustrator 2020 or later.'
} ;
alert(errorMessage) ;
return ;
}
try {
// this script depends on XMPMeta from AdobeXMPScript, so exit if it is disabled
var xmpEnabled = loadXMPLibrary() ;
if(!xmpEnabled) {
var errorMessage = {
ja: 'AdobeXMPScriptが利用可能なIllustratorで実行してください。',
en: 'Please execute in Illustrator with AdobeXMPScript available.'
} ;
alert(errorMessage) ;
return ;
}
// open cloud document for data store
var storePath = 'application_support/com.sttk3.ai.script/store.aic' ;
var doc = openStoreDocument(storePath) ;
if(doc == null) {return ;}
// register scripts
var objectStore = [
{name: 'alert.jsx', code: 'alert("Message from cloud");'}
] ;
var jsonString = JSON.stringify(objectStore) ;
setScripts(doc, jsonString) ;
// save cloud document
doc.save() ;
// close the document once to indicate that the scripts will be taken from the cloud
doc.close() ;
// get scripts from metadata of the document
doc = openStoreDocument(storePath) ;
var jsonString = getScripts(doc) ;
if(jsonString === '') {
var errorMessage = {
ja: 'スクリプトが取得できませんでした。',
en: 'Scripts could not get.'
} ;
alert(errorMessage) ;
return ;
}
var scripts = JSON.parse(jsonString) ;
// execute ExtendScript
execute(scripts[0]) ;
doc.close() ;
} catch(e) {
alert(e) ;
} finally {
unloadXMPLibrary() ;
}
})() ;
/**
* determine if cloud document functions such as openCloudDocument can be supported
* @returns {boolean} available when true
*/
function cloudAvailable() {
return ('openCloudDocument' in app) ;
}
/**
* open cloud document. create it if not exists
* @param {string} cloudPath cloud document path
* @returns {Document|undefined}
*/
function openStoreDocument(cloudPath) {
var res ;
var originalUserInteractionLevel = app.userInteractionLevel ;
try {
// supress error dialog
// https://illustrator.uservoice.com/forums/908050-illustrator-desktop-sdk-scripting-issues/suggestions/49321550-script-cannot-detect-that-app-openclouddocument-fa
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS ;
var doc = app.openCloudDocument(cloudPath) ;
// error trap. the error happens here when the file cannot be opened
doc.name ;
res = doc ;
} catch(e) {
var doc = app.documents.add() ;
doc.saveToCloud(cloudPath) ;
res = doc ;
app.userInteractionLevel = originalUserInteractionLevel ;
}
return res ;
}
/**
* enable AdobeXMPScript
* @returns {boolean} weather successed or not
*/
function loadXMPLibrary() {
var res = false ;
if(!ExternalObject.AdobeXMPScript) {
try{
ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript') ;
res = true ;
} catch(e) {
// skip
}
}
return res ;
}
/**
* disable AdobeXMPScript
*/
function unloadXMPLibrary() {
if(ExternalObject.AdobeXMPScript) {
try{
ExternalObject.AdobeXMPScript.unload() ;
ExternalObject.AdobeXMPScript = undefined ;
} catch(e) {
// skip
}
}
}
/**
* save the script information in the metadata description of the target Illustrator document
* @param {Document} doc target Illustrator document
* @param {string} dstText string to write
*/
function setScripts(doc, dstText) {
// get XMPString from Illustrator document
var xmpPackets = doc.XMPString ;
// create new XMPString using AdobeXMPScript
var xmpMetaObj = new XMPMeta(xmpPackets) ;
if(xmpMetaObj) {
xmpMetaObj.setArrayItem(XMPConst.NS_DC, 'description', 1, dstText) ;
}
var newXMPString = xmpMetaObj.serialize() ;
// set XMPString to Illustrator document
doc.XMPString = newXMPString ;
}
/**
* get the script information in the metadata description of the target Illustrator document
* @param {Document} doc target Illustrator document
* @returns {string} '' if not exists
*/
function getScripts(doc) {
var res = '' ;
// get XMPString from Illustrator document
var xmpPackets = doc.XMPString ;
// get only the necessary info using AdobeXMPScript
var xmpMetaObj = new XMPMeta(xmpPackets) ;
if(xmpMetaObj) {
var nsdc = XMPConst.NS_DC ;
var propName = 'description' ;
var arrayCount = xmpMetaObj.countArrayItems(nsdc, propName) ;
if(arrayCount > 0) {
res = xmpMetaObj.getArrayItem(nsdc, propName, 1).value ;
}
}
return res ;
}
/**
* execute ExtendScript via $.evalFile based on script name and source code
* @param { {name: string, code: string} } scriptItem script info
*/
function execute(scriptItem) {
var tempPath = Folder.temp.fullName ;
var tempScriptFile = new File(tempPath + '/' + scriptItem.name) ;
try {
writeText(scriptItem.code, tempScriptFile) ;
$.evalFile(tempScriptFile) ;
} catch(e) {
alert(e) ;
} finally {
if(tempScriptFile.exists) {
tempScriptFile.remove() ;
}
}
}
/**
* save text as a file
* @param {string} str string to write
* @param {File} fileObj destination file object
* @param {string?} encoding text encoding (optional) utf-8 by default
* @return {File}
*/
function writeText(str, fileObj, encoding) {
if(!encoding) {encoding = 'utf-8' ;}
try {
fileObj.encoding = encoding ;
fileObj.open('w') ;
fileObj.write(str) ;
} finally {
fileObj.close() ;
}
return fileObj ;
}
/**
* read text from a file
* @param {File} fileObj source file object
* @param {string?} encoding text encoding (optional) utf-8 by default
* @return {string}
*/
function readText(fileObj, encoding) {
if(!encoding) {encoding = 'utf-8' ;}
var str = '' ;
try {
fileObj.encoding = encoding ;
fileObj.open('r') ;
str = fileObj.read() ;
} finally {
fileObj.close() ;
}
return str ;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment