| /** | |
| * @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 ; | |
| } |