Copy link to clipboard
Copied
Has anyone come across anything like JSON.strigify() for native illustrator objects? I'm looking for a was to stringify and parse objects and type. I've tried a couple JSON implimentations suggested in other posts, but I get stack overrun errors on stringify().
Copy link to clipboard
Copied
Do you mean using JSON.stringify for any object within a JSX file, or using JSON.stringify on specific objects like app? If the latter there shouldn't be a need to grab every single property and method of a given native object. What are you actually trying to achieve?
What code gives you the stack overrun error?
Copy link to clipboard
Copied
I need to be able to re-create groups with path items, complex paths, point text, etc. from within a script. The exact configuration of the objects may change frequenty so I can't hard code the object creation - I need a way to quickly stringify a group so it can be embedded/updated as a variable in a script that will then parse it back into the document.
The stack overrun comes if I create a basic rectangle in illustrator and then try JSON.stringify() on it. I've tried 3 different JSON libraries that I've found. But all seem to get into infinite loops trying to work with the Layers... I think because of child/parent circular relationships...
Copy link to clipboard
Copied
Can you give an example? By "re-create" do you just mean duplicate? Why not select the objects, copy them to clipboard, then pasteInFront, clear selection?
You're trying to JSON.stringify them to return them to a CEP panel? What's the need for JSON.stringify?
Copy link to clipboard
Copied
Not sure I understand what you mean by this part referring to JSON.stringify:
"I need a way to quickly stringify a group so it can be embedded/updated as a variable in a script that will then parse it back into the document."
Is this the same script or a separate script?
Copy link to clipboard
Copied
One approach could be to do it via SVG.
You can export/import SVGs to the filesystem, or you may be able to take advantage of a clipboard hack...
When you copy a selection to the clipboard in Illustrator it serialises it to SVG.
As far as I can tell illustrator doesn't provide a method to directly access the clipboard contents (although there are some workarounds on Windows to do this), but what you should be able to do is create a temporary textframe on the document and paste the clipboard contents into its content property, then read the content back into your javascript to get the raw SVG text.
To paste the SVG back into the file you'd do the reverse.
Copying the text to the clipboard may be a bit tricky, but there seem to be a few discussions about how to do it, like this one: https://community.adobe.com/t5/illustrator/is-it-possible-to-copy-text-to-the-clipboard-in-illustrat...
Copy link to clipboard
Copied
#target illustrator
function test () {
"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function quote(t){
return escapable.lastIndex=0,escapable.test(t)?'"'+t.replace(escapable,function(t){var e=meta[t];
return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}
function str(t,e){var n,r,o,f,u,i=gap,p=e[t];switch(p&&"object"==typeof p&&"function"==typeof p.toJSON&&(p=p.toJSON(t)),
"function"==typeof rep&&(p=rep.call(e,t,p)),typeof p){case"string":return quote(p);case"number":return isFinite(p)?String(p):"null";
case"boolean":case"null":return String(p);case"object":if(!p)return"null";if(gap+=indent,u=[],"[object Array]"===Object.prototype.toString.apply(p)){
for(f=p.length,n=0;f>n;n+=1)u[n]=str(n,p)||"null";return o=0===u.length?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+i+"]":"["+u.join(",")+"]",gap=i,o}
if(rep&&"object"==typeof rep)for(f=rep.length,n=0;f>n;n+=1)"string"==typeof rep[n]&&(r=rep[n],o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o));
else for(r in p)Object.prototype.hasOwnProperty.call(p,r)&&(o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o));return o=0===u.length?"{}":gap?"{\n"+gap+
u.join(",\n"+gap)+"\n"+i+"}":"{"+u.join(",")+"}",gap=i,o}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){
return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+
f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){
return this.valueOf()});var cx,escapable,gap,indent,meta,rep;"function"!=typeof JSON.stringify&&
(escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,n){var r;
if(gap="",indent="","number"==typeof n)for(r=0;n>r;r+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=e,
e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),
"function"!=typeof JSON.parse&&(cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
JSON.parse=function(text,reviver){function walk(t,e){var n,r,o=t[e];if(o&&"object"==typeof o)for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&
(r=walk(o,n),void 0!==r?o[n]=r:delete o[n]);return reviver.call(t,e,o)}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&
(text=text.replace(cx,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),
/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@")
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]")
.replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;
throw new SyntaxError("JSON.parse")})}();
function ArtNode (typename, name, note, children, extraProps) {
this.typename = typename;
this.name = name;
this.note = note;
if (typename == "GroupItem") {
this.children = children || [];
}
if (extraProps) {
for (var all in extraProps) {
this[all] = extraProps[all];
}
}
};
function getArtTree (rootArt) {
function getNodeInfo (art) {
var thisTypename = art.typename;
var extraProps = null;
switch (thisTypename) {
case "TextFrame":
extraProps = { "contents" : art.contents };
break;
case "SymbolItem":
extraProps = { "symbol_name" : art.symbol.name };
break;
default:
break;
}
var children = null;
if (thisTypename == "GroupItem") {
children = [];
var thisPageItem, newObj;
for (var i = 0; i < art.pageItems.length; i++) {
thisPageItem = art.pageItems[i];
newObj = getNodeInfo(thisPageItem);
children.push(newObj);
}
}
var thisNode = new ArtNode(
thisTypename,
art.name,
art.note,
children,
extraProps
);
return thisNode;
};
return getNodeInfo(rootArt);
};
var doc = app.activeDocument;
var sel = doc.selection[0];
var treeObj = getArtTree(sel);
alert(JSON.stringify(treeObj, null, 2));
};
test();
{
"typename": "GroupItem",
"name": "",
"note": "",
"children": [
{
"typename": "GroupItem",
"name": "",
"note": "",
"children": [
{
"typename": "TextFrame",
"name": "MyText",
"note": "",
"contents": "hey!"
},
{
"typename": "GroupItem",
"name": "SpecialGroup",
"note": "",
"children": [
{
"typename": "GroupItem",
"name": "",
"note": "",
"children": [
{
"typename": "PathItem",
"name": "",
"note": "Note here."
},
{
"typename": "SymbolItem",
"name": "",
"note": "",
"symbol_name": "Gerbera"
}
]
},
{
"typename": "PathItem",
"name": "",
"note": ""
}
]
},
{
"typename": "GroupItem",
"name": "",
"note": "",
"children": [
{
"typename": "PathItem",
"name": "",
"note": "A note."
},
{
"typename": "PathItem",
"name": "MyRect",
"note": "MyRect's note."
}
]
}
]
},
{
"typename": "CompoundPathItem",
"name": "",
"note": ""
}
]
}
Copy link to clipboard
Copied
Ugh these forums are driving me nuts.
It took out all my text commentary but - it said"
Try this, the image here produces the following output there.
You can add shared properties such as x/y coordinates that are shared by all art items directly on the ArtNode class, and add any custom property which may contain any kind of data by adding statements to the switch block. In my example, you can see I've got a symbolItem's symbol name and a text frame's contents. In a similar way you could get fill or stroke colors widths & overprints of a pathItem.