Copy link to clipboard
Copied
I am wondering if anyone has been able to figure out what kind of "LiveEffectXML" is a parameter to PageItem.applyEffect()
It's been years since this feature has been out, but no documentation anywhere.
Hi Silly-V, I figured it out, with big big, and I mean BIG help from Adobe's Sanjay K
// apply offset path live effect to selected path
var idoc = app.activeDocument;
var ipath = idoc.selection[0];
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="R mlim 4 R ofst 20 I jntp 2 "/></LiveEffect>';
ipath.applyEffect(xmlstring);
//mlim is the MiterLimit Value “4”, ofst is the Offset Value “20”, jntp is the Join Type “2” for Miter.
Copy link to clipboard
Copied
They may be SVG filter?
Copy link to clipboard
Copied
Hi Silly-V, I figured it out, with big big, and I mean BIG help from Adobe's Sanjay K
// apply offset path live effect to selected path
var idoc = app.activeDocument;
var ipath = idoc.selection[0];
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="R mlim 4 R ofst 20 I jntp 2 "/></LiveEffect>';
ipath.applyEffect(xmlstring);
//mlim is the MiterLimit Value “4”, ofst is the Offset Value “20”, jntp is the Join Type “2” for Miter.
Copy link to clipboard
Copied
Way to go! This shall prove infinitely useful, no doubts about it. Thanks for the research.
Copy link to clipboard
Copied
Nice work Carlos + Sanjay.
Curious (unable to test myself), does the applyEffect occur and get applied without the effect dialog appearing and no user interaction required, with the provided parameters applied?
Copy link to clipboard
Copied
Hi W_J_T, that's correct, Effects get applied with the supplied parameters, no dialog shown.
Thanks
Copy link to clipboard
Copied
Neat-o! Thanks for the confirmation Carlos, again great job.
Copy link to clipboard
Copied
Okay, let the experimentation begin.
First, I wanted to get the FXG file, but have no CS5 or CS6 where I am at the moment, so I used the scripting command to do a SaveAs using new FXGSaveOptions. This saved the current file, but not as fxg, rather as .ai. I renamed the file to fxg manually, but I suspect that one could simply open the ",ai" file as text anyway.
Well, in my result which came from CC2015, as there is no UI dialog FXG save option and no "show code" option, I did not get my XML string as described in Carlos' post. However, the same info is present in the FXG text, which for my simple 1-rectangle file consumed over 20,000 lines. Doing a search for my desired effect, Offset Path, I saw a structure from where the data can be also obtained if one doesn't have CS5 or CS6 and has to save the file like I did to get the effect parameter string data.
Then I was able to thus isolate this section:
/BasicFilter :
(Adobe Offset Path) 1 0 /Filter ,
1 /Visible ,
(OffsetPath.aip) /PluginFileName ,
(Offset Path) /Title ,
/Dictionary : /NotRecorded ,
0 /Int (jntp) ,
10 /Real (ofst) ,
4 /Real (mlim) ,
; /Dict ;
From where you can tell which parts relate to the XML string as Carlos has described:
<LiveEffect name="Adobe Offset Path"><Dict data="R mlim 4 R ofst 20 I jntp 2 "/></LiveEffect>
The name attribute in LiveEffect tag comes from the line with "1 0 /Filter ,"
The various attributes are from the lines beflow the /Dictionary : /NotRecorded ," and their number values (in case of this effect) are followed by the "datatype" (?) name, which is then abbreviated into a 1st capital letter in the effect string, and then the name which is in parentheses.
When copied, pasted and spliced and chopped so as to resemble the working example of Carlos, these pieces of strings can be used in the live effect string in any order.
Interestingly, the Join Type for this Offset Path effect does not quite correspond with the dropdown menu in the effect's actual UI dialog: the 0 value is for "Round" which is the 2nd (middle) item in the dropdown, the 1 value is for "Bevel" which is the 3rd item, and 2 is for "Miter" which is the 1st item.
Doing numbers from 3 on up for the joint type will default this effect to "Miter".
Using this new insight, I'm able to produce the all-powerful Transform effect dynamically.
In this example, the horizontal move is created using the width of the selection.
#target illustrator
function test(){
var doc = app.activeDocument;
var p = doc.selection[0];
var effectStr_2 =
'<LiveEffect name="Adobe Transform">' +
'<Dict data="' +
'R scaleH_Factor 1 ' +
'R moveV_Pts 0 ' +
'R scaleV_Percent 100 ' +
'I pinPoint 4 ' + // note the anchor point parameter- it goes from top-left (0) to bottom-right (8)
'B scaleLines 0 ' +
'I numCopies 1 ' +
'B randomize 0 ' +
'R rotate_Radians 0 ' +
'R moveH_Pts ' + p.width + ' ' +
'R scaleV_Factor 1 ' +
'B reflectY 0 ' +
'B reflectX 0 ' +
'R rotate_Degrees 0 ' +
'R scaleH_Percent 100 ' +
'B transformPatterns 0' +
'"/>' +
'</LiveEffect>';
p.applyEffect(effectStr_2);
}
test();
There is a problem in that we can't edit existing effects, and we can't apply new instances of effects with ability to override old ones. They simply get stacked on and on inside the appearance palette. For those uses where a one-time application is OK, or expansion soon follows, this probably doesn't matter. And for those that it does matter to, it is possible to record a "Reduce to Basic Appearance" action and run it with the script immediately. Another non-optimal solution which may work for some situations is having a pre-included set of 'default' graphic styles in the document, which could be called later to be applied onto the art, overriding any other effects and resetting it back.
Copy link to clipboard
Copied
great, thanks for adding your findings Silly, seeing the FXGSaveOptions in the documentation and Object browser, I thought we could save as fxg from CC
Copy link to clipboard
Copied
Maybe no bother using the FXGSaveOptions(it turned out to be just ai file, not FXG at all), just save ai file without compression, open it with text editer such as SublimeText, using regex mode to search and replace the data.
Get the name:
(?<=/BasicFilter :\n\()[^)]*(?=\) 1 0 /Filter)
Get and format the dict data: find
^([\d.]*) /(\w)[^(\n]*\((\w+)\).+
replace with
'\2 \3 \1' +
So this is another code strings:
'<LiveEffect name="Adobe Zigzag">' +
'<Dict data="' +
'R roundness 1' +
'R amount 10' +
'R ridges 3' +
'R relAmount 0' +
'R absoluteness 1' +
'"/>' +
'</LiveEffect>';
And now its easy to get all these LiveEffectXML, also we can write functions for reuse.
Copy link to clipboard
Copied
The instructions on page linked doesn't explain if one wants to get a live effect such as the warp tool, considering you can't apply the warp tool then save the scene as a FXG file and get the XML data from the use of the warp tool ?
Copy link to clipboard
Copied
I know this is a long shot on such an old thread, but I'm new to scripting and a little desperate to solve this. I was curious what would need to be changed in this script to apply the effect to all objects on the artboard. When I run the script, it is only applying the effect to one object.
Copy link to clipboard
Copied
you'll have to loop through your items and apply the effect to each item at a time.
unless the effect you want to apply takes no arguments, in that case you could use the equivalent executeMenuCommand method if there is one.
Copy link to clipboard
Copied
Yeah, its strange, even with all of the objects selected, it'll only apply the Offset Path to a single item.
Copy link to clipboard
Copied
that's how it works, it only applies the effect to a single object. Selecting one or more items is irrelevant. You don't have to select the item to apply the effect. Selecting is actually discouraged, only select items when absolutely necessary.
Copy link to clipboard
Copied
This is a great thread, I was following moluapple's method through an uncompressed AI file when I noticed that these Live Effects look like siblings to what I optimistically hope might be other accessible things. In my file, the Stroke Offset effect shows up mixed in with Stroke and Fill effects:
/Part ,
/BasicFilter :
(Stroke Style Filter) 0 0 /Filter ,
1 /Visible ,
2 /FillOrStroke ,
/Dictionary : /NotRecorded ,
/StrokeStyle : 0 R
0.011535820551217 0.457404434680939 0.82201874256134 0 0.96078431372549 0.607843137254902 0.270588235294118 XA
0 1 0 0 0 Xy
0 J 0 j 2 w 1 M []0 d
0 XR
1 0 Xd
/Def ;
(StrokeStyle) ,
; /Dict ;
/Part ,
/CompoundFilter :
(Chain Style Filter) 0 0 /Filter ,
1 /Visible ,
/BasicFilter :
(Adobe Stroke Offset) 1 0 /Filter ,
1 /Visible ,
(Illustrator.exe) /PluginFileName ,
(Stroke Offset Live Effect) /Title ,
2 /FillOrStroke ,
/Dictionary : /NotRecorded ,
(Inside) /String (DisplayString) ,
/StrokeStyle : 0 R
0 0 0 0 1 1 1 XA
0 1 0 0 0 Xy
0 J 0 j 1.8 w 1 M []0 d
0 XR
1 0 Xd
/Def ;
(StrokeStyle) ,
'B StrokeOffsetInside 1' +
; /Dict ;
/Part ,
/BasicFilter :
(Blend Style Filter) 0 0 /Filter ,
1 /Visible ,
/Dictionary : /NotRecorded ,
/BlendStyle : 0 0.6 0 0 0 Xy
0 J 0 j 1 w 10 M []0 d
0 XR
/Def ;
(BlendStyle) ,
; /Dict ;
/Part ,
The format looks very similar too -- moluapple's RegExp picks up "Adobe Stroke Offset" which looks to be "Stroke Style Filter" in the effect above. I'm curious if strokes and fills could be accessed as LiveEffects and if what we're looking at is how the Appearance panel is handled. Would it be possible to access a stroke through this method then use PageItem.tag to keep track of multiple strokes? I don't know anything about C++, but I wondered if the way this worked was through the AILiveEffectSuite:
If so, would that mean that a script could potentially have access via app.sendScriptMessage? Or am I completely out in left field on this?
Copy link to clipboard
Copied
Yes, when you make own c++ .aip plugin, you can expose some functionality to scripts and the .jsx scripts can then be used to make your separate .aip plugin features available to one overall .jsx script that may need to be used to utilize any amount of features from the various .aip plugins.
Copy link to clipboard
Copied
Is there a way to find out the mechanism behind PageItem.applyEffect(), as in which plugin or Suite it's exposed to, if applicable? As in, trying to apply the XML effect via app.sendScriptMessage() through the above plugin's function (AILiveEffectSuite) as a gauge for whether or not that's the mechanism behind the applyEffect() method?
Your pragmatism is no match for my idealism sir, I want multiple strokes so very much
Copy link to clipboard
Copied
The app.sendScriptMessage was added later, and deals with custom plugins, the only documented piece in the javascript guide pdf is this:
So if there are such accessible strings available for the various default plugins, I have not yet seen such a list, but most likely they are not there because this scripting command was added way later. I'd love to be wrong..
Copy link to clipboard
Copied
I've been admiring this thread for a while. I appologise if the connection has already been made (particuarly to ten_a) - I've not seen it though; I was googling for more info on the topic, and came this post in Japanese where 投稿者: ten_a shares some of their own live effect code:
https://translate.google.com/translate?sl=auto&tl=en&u=https://ten-artai.com/2015/12/318/#Drop Shadow
<LiveEffect name="Adobe Drop Shadow"><Dict data="R horz 7 I blnd 1 R opac 0.75 R dark 100 B pair 1 I csrc 0 R vert 7 R blur 5 B usePSLBlur 1 I Adobe Effect Expand Before Version 16 " /></LiveEffect>
#Fuzzy Mask
<LiveEffect name="Adobe Fuzzy Mask"><Dict data="R Radius 5 " /></LiveEffect>
#Inner Grow
<LiveEffect index="0″ major="1″ minor="0″ name="Adobe Inner Glow"><Dict data="I gtyp 1 I blnd 2 R opac 0.75 R blur 5 “><Entry name="gclr" valueType="F"><Fill color="1 0 0 0 0″/></Entry></Dict></LiveEffect>
#Outer Grow
<LiveEffect name="Adobe Outer Glow"><Dict data="I Adobe Effect Expand Before Version 16 I blnd 2 R opac 0.75 R blur 5 B usePSLBlur 1 " /></LiveEffect>
#Scribble Fill
<LiveEffect name="Adobe Scribble Fill"><Dict data="R Spacing 5 R EdgeOverlap 0 R Scribbliness 0.05 R StrokeWidth 3 R Angle 30 R EdgeOverlapVariation 5 R SpacingVariation 0.5 R ScribbleVariation 0.01 " /></LiveEffect>
#Round Corners
<LiveEffect name="Adobe Round Corners"><Dict data="R radius 10 “/></LiveEffect>
#Outline Type
<LiveEffect index="0″ isPre="1″ major="1″ minor="0″ name="Adobe Outline Type"><Dict /></LiveEffect>
#Outline Stroke
<LiveEffect index="0″ major="1″ minor="0″ name="Adobe Outline Stroke"><Dict /></LiveEffect>
#Offset Path
<LiveEffect name="Adobe Offset Path"><Dict data="R mlim 4 R ofst 10 I jntp 2 " /></LiveEffect>
#Zigzag
<LiveEffect name="Adobe Zigzag"><Dict data="R roundness 0 R absoluteness 1 R relAmount 10 R ridges 4 R amount 10.006 " /></LiveEffect>
#Free Disort
<LiveEffect name="Adobe Free Distort"><Dict data="R src3h 278 R src2h 178 R dst2v -263 R src2v -263 R src0h 178 R dst2h 178 R src3v -263 R dst3v -263 R dst0v -163 R src1h 278 R src1v -163 R src0v -163 R dst0h 178 R dst1v -163 R dst1h 278 R dst3h 278 " /></LiveEffect>
#Punck & Bloat
<LiveEffect name="Adobe Punk and Bloat"><Dict data="R d_factor 10 " /></LiveEffect>
#Twirl
<LiveEffect name="Adobe Twirl"><Dict data="R angle 30 " /></LiveEffect>
#Pathfinder
<LiveEffect name="Adobe Pathfinder"><Dict data="R TrapTintTolerance 0.05 B ExtractUnpainted 1 B TrapConvertCustom 0 R TrapAspect 1 B ConvertCustom 1 R TrapMaxTint 1 R Mix 0.5 B RemovePoints 0 I Command 0 R TrapThickness 0.25 R TrapTint 0.4 B TrapReverse 0 R Precision 10 “><Entry name="DisplayString" value="" valueType="S" /></Dict><LiveEffect>
#3D Effect
<LiveEffect name="Adobe 3D Effect"><Dict data="B showHiddenSurfaces 0 R cameraPerspective 0 I rotationPresetKey 9 B paramsDictionaryInitialized 1 I 3Dversion 2 B extrudeCap 1 R mat_12 -0.278 R mat_13 0 R mat_20 -0.456 R mat_21 0.248 R mat_22 0.855 R mat_23 0 R mat_30 0 R mat_31 0 R mat_32 0 R mat_33 1 R rotX -18 R rotY -26 R rotZ 8 R revolveAngle 360 B revolveCap 1 R revolveOffset 0 I revolveAxisMode 0 I surfaceStyle 3 R surfaceAmbient 50 R surfaceMatte 40 R surfaceGloss 10 R blendSteps 25 B invisibleGeo 0 I shadeMode 3 B preserveSpots 0 I numLights 1 B shadeMaps 0 I numArtMaps 0 R mat_11 0.961 R mat_10 0.002 R mat_03 0 R mat_02 0.438 R mat_01 0.125 R mat_00 0.89 I effectStyle 0 R bevelHeight 4 B bevelExtentIn 1 R extrudeDepth 50 “><Entry name="shadeColor" valueType="F"><Fill color="1 0 1 1 0″/></Entry><Entry name="light0″ valueType="D"><Dict data="R lightDirX 0.39 R lightDirY 0.33 R lightDirZ -0.85 R lightPosX 0 R lightPosY 0 R lightPosZ -1 R lightIntensity 1 " /></Entry><Entry name="DisplayString" value="3D " valueType="S"/></Dict></LiveEffect>
I've tested most of them, and they were grand!
Copy link to clipboard
Copied
It's worth mentioning that @m1b has done some really nice work on live effects:
https://community.adobe.com/t5/illustrator/scripting-live-effects/m-p/11744702
Copy link to clipboard
Copied
It's worth mentioning that @m1b that has done some really nice work on live effects:
https://community.adobe.com/t5/illustrator/scripting-live-effects/m-p/11744702
By @femkeblanco
Yes, I've been admiring that one too 🙂