Copy Effect with Parameters

Find out why the . goes before the /

Moderator: Paul Tuersley

Post Reply
jordanwade33
Posts: 16
Joined: December 8th, 2014, 11:11 pm

I'm struggling to come up with an easy solution to my problem, but I think there should be one out there. What I'm looking to do is to use a script to copy an effect from one layer to another along with it's parameters. The trick is that every effect has a different amount of properties and can have sub-properties at different property depths. I can easily find the effect's matchname and add it to layer with .Effects.addProperty(matchname) but that doesn't carry it's parameters.

Is the only way to accomplish this by cycling the script through all the possible parameters of an effect, storing the values in an array, and then running through the new effect on a different layer and retrieve the value through the array? Does anyone have a better idea? I'm still new to scripting so it's a battle between efficiency and how I think things should work. Thanks!
beginUndoGroup
Posts: 81
Joined: November 27th, 2012, 6:41 am

It's not easy, and even if you write a decent function that does it, it will frequently generate errors due to properties for which script cannot read/set values, like curves, histogram, etc: all properties that have propertyValueType: CUSTOM_VALUE or NO_VALUE.

A workaround it to use the menu commands "Copy" and "Paste".
In CC, there are also alternatives: "Copy with Property Links" and "Copy with Relative Property Links" that can be useful too.
I've just tried this function, it seems to work:

Code: Select all

function copyPropertyBase(source, target){
	
	if (source.propertyDepth<1) {alert("Cannot copy a layer into another!"); return;};
	
	var layer1 = source.propertyGroup(source.propertyDepth);
	var comp1 = layer1.containingComp;
	var time1 = comp1.time;
	
	var layer2 = target.propertyDepth === 0 ? target : target.propertyGroup(target.propertyDepth);
	var comp2 = layer2.containingComp;
	var time2 = comp2.time;
	
	comp1.time=comp2.time=0;
	
	comp1.openInViewer();
	app.executeCommand(app.findMenuCommandId("Deselect All"));
	try{source.selected=true}catch(e){alert(source.name + ": cannot copy this property:\r\r" + e.message); comp1.time=time1; comp2.time=time2; return;};
	app.executeCommand(app.findMenuCommandId("Copy"));
	layer1.selected = false;
	
	if (comp2!=comp1){
		comp2.openInViewer();
		app.executeCommand(app.findMenuCommandId("Deselect All"));
		};
	try{target.selected=true}catch(e){alert(target.name + ": sorry, cannot copy into this property:\r\r" + e.message); comp1.time=time1; comp2.time=time2; return;};
	app.executeCommand(app.findMenuCommandId("Paste"));
	
	comp1.time=time1;
	comp2.time=time2;
	
	return;
	};


A few tests:

Code: Select all

var comp = app.project.activeItem;
var layer1 = comp.layer("ORIGINAL");
var layer2 = comp.layer("COPY");

// copy effect(3):
while(layer1.effect.numProperties<3) layer1.effect.addProperty("ADBE Slider Control");
copyPropertyBase(layer1.effect(3), layer2);                                                 // this adds a new effect
copyPropertyBase(layer1.effect(3), layer2.effect(layer2.effect.numProperties)); // this does not add an effect, but copies the content of the source effect into the target effect

// copy anchorPoint and position:
copyPropertyBase(layer1.transform.position, layer2);
copyPropertyBase(layer1.transform.anchorPoint, layer2);

// copy one (locked) mask
if (layer1.mask.numProperties===0) layer1.mask.addProperty("ADBE Mask Atom");
layer1.mask(1).locked = true;
copyPropertyBase(layer1.mask(1), layer2);

// copy all layers styles
copyPropertyBase(layer1.layerStyle, layer2);

// etc
jordanwade33
Posts: 16
Joined: December 8th, 2014, 11:11 pm

I just tried the function that you came up with and it works great for what I need it to. It's sad to admit, but it never occurred to me to just call the menu items to copy and paste. Thanks so much for the help!
crossrad
Posts: 9
Joined: May 1st, 2021, 1:36 pm
Contact:

Thanks very much for this. I made use of this technique for copying effects and it works great ... mostly, but I have come across a case where the copy did not happen. No error messages were generated. I implemented a retry mechanism, and in a substantial regression test the copy had to be retried a second time.

Code: Select all

    function copyPropertyBase(source, target) {

        if (source.propertyDepth < 1) {
            alertWrapper("Cannot copy a layer into another!");
            return
        }

        var layer1 = source.propertyGroup(source.propertyDepth);
        var comp1 = layer1.containingComp;
        var time1 = comp1.time;

        var layer2 = target.propertyDepth === 0 ? target : target.propertyGroup(target.propertyDepth);
        var comp2 = layer2.containingComp;
        var time2 = comp2.time;

        var len = layer2.Effects.numProperties;
        var iTry = 0;
        do {
            comp1.time = comp2.time = 0;
            comp1.openInViewer();
            app.executeCommand(app.findMenuCommandId("Deselect All"));

            try {
                source.selected = true
            } catch (e) {
                alertWrapper(source.name + ": cannot copy this property:\r\r" + e.message);
                comp1.time = time1;
                comp2.time = time2;
                return
            }

            app.executeCommand(app.findMenuCommandId("Copy"));
            layer1.selected = false;

            if (comp2 != comp1) {
                comp2.openInViewer();
                app.executeCommand(app.findMenuCommandId("Deselect All"));
            };

            try {
                target.selected = true
            } catch (e) {
                alertWrapper(target.name + ": sorry, cannot copy into this property:\r\r" + e.message);
                comp1.time = time1;
                comp2.time = time2;
                return
            }

            app.executeCommand(app.findMenuCommandId("Paste"));
            iTry++;
        } while ((iTry < 5) && (layer2.Effects.numProperties <= len));
        if (iTry > 1) {
            $.writeln ("Tries (" + iTry + ") required to paste property " + layer2.Effects.numProperties + " to layer " + layer2.name);
        }
        comp1.time = time1;
        comp2.time = time2;

        return
    }

Results:

Code: Select all

Test Mixed_exp_keyframe done
Tries (2) required to paste property 1 to layer Light
Test MixedEffects done
Test CopyBezier done
Test ExpSeparateStatic done
Test ExpSeparateExpression done
Test ExpCombinedStatic done
Test ExpCombinedExpression done
Test KeyframeSeparateStatic done
Test KeyframeSeparateKeyframed done
Test KeyframeCombinedStatic done
Test KeyframeCombinedKeyframed done

I found that the problem did not occur if I put the troublesome test FIRST in the regression, and 1 in 10 runs of the identical regression test it doesn't occur. So it looks like a low level problem in After Effects that I have no ability to investigate further.

DangerD
Posts: 1
Joined: November 26th, 2023, 10:50 am

Works great, is there any way to make something similar for Transform?

Post Reply