• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers

Merge fixed content inside specific groups

Explorer ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Hi everyone.

I've got this script that copy the layer "_fixed obj" inside every other layers (except the one which name start with "dima_". It works fine what i want it to place the "_fixed obj" inside a specif group nested into the layers.

Here's the code:

/*
* Description: An Adobe Illustrator script that combine template layers and content layers
* Usage: Rename all "template" layers with an underscore "_" as the first character. Rename all "content" layers with any suitable names
* This is an early version that has not been sufficiently tested. Use at your own risks.
* License: GNU General Public License Version 3. (http://www.gnu.org/licenses/gpl-3.0-standalone.html)
*
* Copyright (c) 2009. William Ngan.
* http://www.metaphorical.net

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


var doc = app.activeDocument;
var origlayers = new Array();


// Record all original content layers
for(var i=0; i<doc.layers.length; i++) {
	
	if ( !(doc.layers[i].name.charAt(0)=='_') ) {
		origlayers.push( doc.layers[i].name );
	}
}

// Generate dima layers
for(var i=0; i<origlayers.length; i++) {
	getContent( origlayers[i] );
}


// Distinguish non-dima layers and dima layers by visibility
origlayers = new Array();
for(var i=0; i<doc.layers.length; i++) {
	
	// non-dima
	if (doc.layers[i].name.substr(0,5)!='dima_') {
		doc.layers[i].visible = true;
		origlayers.push( doc.layers[i].name );

	// dima
	} else {
		doc.layers[i].visible = false;
	}
}


// Remove non-dima layers
for(var i=0; i<origlayers.length; i++) {
	doc.layers.getByName (origlayers[i]).remove();
}

// show first dima layer
doc.layers[0].visible = true;

/**
* opens a resource file and copy the specific layer to page
* @Param layername the name of the layer
*/
function getContent(layername) {
	
	// open resource file
	var tempdoc = null;
	
	try {

	} catch (err) {
		throw new Error( 'Cannot create new document' );
	}

	// create a new layer
	var temp_layer = doc.layers.add();
	temp_layer.name = 'dima_'+layername;
	temp_layer.visible = true;
	var gg = temp_layer.groupItems.add();

	// get specified layer. all unrelated layers set to invisible
	for(var i=doc.layers.length-1; i>=0; i--) {
		
		if (doc.layers[i].name.charAt(0)=='_') { // persistent layers with "_"
			doc.layers[i].visible = true;	
			group( gg, doc.layers[i].pageItems, true );
			
		} else if (doc.layers[i].name.substr(0,5)!='dima_') { // not dima layer
			doc.layers[i].visible = false;	
		}
	}

	try {
		var content = doc.layers.getByName(layername);
	} catch (err) {
		throw new Error('Cannot get contents from '+layername+'* layer');
	}

	// group content
	content.visible = true;
	group( gg, content.pageItems, true );

}


function group( gg, items, isDuplicate ) {

	for(var i=items.length-1; i>=0; i--) {

		if (items[i]!=gg) { 
			if (isDuplicate) {
				newItem = items[i].duplicate (gg, ElementPlacement.PLACEATEND);
			} else {
				items[i].move( gg, ElementPlacement.PLACEATEND );
			}
		}
	}

}
app.activeDocument.layers.getByName('dima_dima_var').remove();

 

Here's the screenshot of the starting layers composition:

 

start.JPG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

After the script it's like this:

 

end.JPG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I'd like if those fixed objects will be place inside the relative group.

So the groups of fixed objects named "back" will go into the group named "back", the ones named "front" will go into "front" and so on.

 

Note: every layers ("dima_top_X") will have the same items structure inside of it, whit the same names.

 

Is it possible?

Please tell me if i need to provide more info to hele me.

Thanks.

TOPICS
Scripting

Views

1.2K

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Dec 05, 2022 Dec 05, 2022

Here's a version that gets the template layer first and doesn't need a selection.

- Mark

 

 

/**
 * Duplicates *template* items (all page items
 * in templateLayerName) into groups named to
 * match name of template item. For example,
 * an item "front" (in layer "_fixed obj") will
 * be duplicated into every GroupItem named "front"
 * and that has clipping mask called "front".
 * @author m1b
 * @version 2022-12-06
 * @discussion https://community.adobe.com/t5/illustrator-discussions/merge-fixed
...

Likes

Translate

Translate
Community Expert ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Hi @Magenta s.r.l., there's a lot going on here. To make it easier for us to understand, can you make a stripped-down test file that only has the fixed objects and one other layer, with just the necessary page items? And show screen shots of the layers panel showing how you would like it to look before and after? Make sure all layers are visible in the screenshots. This will help us a lot.

 

For example it looks like the fixed object named "front" should actually replace the items named front in the other layers? Also why does the script reverse the order of all the items in the layer? Is that desirable?

- Mark

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Hi @m1b and thank you for your reply.

Here's you can find a file test as requested: file test

This is the ""before" layers panel:

 

before.JPG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Here's the "after" layers panel:

 

after.JPG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

As you can see the elements inside the layer "_fixed obj" are now inside the groups in the layer "dima_top 116"

Of course those elements has to be duplicated into all the others layers's group.

So, if the element is called "front" it goes in every "front" named group in each layers.. and so on.

In this example there are fixed elements called "front" and back" only but it could happen that i have some fixed elements called "slv Sx" or "slv Dx"... the point is these elements have to go into the group with the same name contained in all layers (except "dima_var" layer but the script already prevent it).

The items or layers you see hidden have to stay that way.

 

quote

Also why does the script reverse the order of all the items in the layer? Is that desirable?

 

Actually, not ;).. i found this script as it is. I mean i've just modified the layers names and in  the end i replaced

 

PLACEATBEGINNING

 

with

 

PLACEATEND

 

'cause the fixed objects have to stay on top of the items in the group and finally i added

app.activeDocument.layers.getByName('dima_dima_var').remove();

 

I don't know if those modifications caused the reversing or not.. but it would be better without the reversing for sure, can you make it happen?

 

If you need more info, just ask.

Thank you in advance!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Hi @Magenta s.r.l., the script you are using seems to have a lot of unwanted side effects. I hope you don't mind but it was much easier for me just to write a new script that directly does what you are asking. Maybe you can learn from what I've done here and adapt to your specific needs. Let me know if it helps.

 

To use script, select the template items (ie. the items that will be duplicated).

- Mark

 

 

 

/**
 * Duplicates selected *template* items into
 * groups named to match name of template item.
 * For example, a selected item "front" will be
 * duplicated into every GroupItem named "front"
 * and that has clipping mask called "front".
 * @author m1b
 * @version 2022-12-06
 * @discussion https://community.adobe.com/t5/illustrator-discussions/merge-fixed-content-inside-specific-groups/m-p/13396929
 */
(function () {

    // must have something selected

    var doc = app.activeDocument;

    if (doc.selection == undefined) {
        alert('Please select the template items and try again.');
        return;
    }

    // collect template items and names
    var templateItems = [];

    for (var i = doc.selection.length -1; i >= 0 ; i--)
        templateItems.push(doc.selection[i]);


    // find clipping items with same name as templates
    for (var i = 0; i < doc.groupItems.length; i++) {

        var grp = doc.groupItems[i];

        for (var j = 0; j < templateItems.length; j++) {

            var templateItem = templateItems[j];

            if (
                grp.hidden !== true
                && grp.name == templateItem.name
                && grp.clipped == true
                && grp.pathItems.length > 0
                && grp.pathItems[0].name == templateItem.name
                && grp.pathItems[0].clipping == true
            ) {

                // duplicate the templateItem into the group
                var dup = templateItem.duplicate();
                dup.move(grp.pathItems[0], ElementPlacement.PLACEAFTER);
                dup.selected = false;

            }

        }

    }

})();

 

 

 

BEFOREBEFOREAFTERAFTER

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Hi @m1b don't worry, i don't mind at all, please be my guest and do whatever adjustments you want!

As mentioned, the script was like that and unfortunately i'm not expert enough to see nor to correct those unwanted side effects, so thank you for that!

One good advantage of that script tho was that i didn't have to select the layers with the templates, it recognized it cause the name started with an underscore.

Is it possible to have something like that?

Also i have to get rid of the fixed obj layer ater all so i guess i could add this

app.activeDocument.layers.getByName('_fixed obj').remove();

at the end of the script. Unless you find a more elegant way to do it 😉

 

Thank you a lot, waiting for your reply!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 05, 2022 Dec 05, 2022

Copy link to clipboard

Copied

Here's a version that gets the template layer first and doesn't need a selection.

- Mark

 

 

/**
 * Duplicates *template* items (all page items
 * in templateLayerName) into groups named to
 * match name of template item. For example,
 * an item "front" (in layer "_fixed obj") will
 * be duplicated into every GroupItem named "front"
 * and that has clipping mask called "front".
 * @author m1b
 * @version 2022-12-06
 * @discussion https://community.adobe.com/t5/illustrator-discussions/merge-fixed-content-inside-specific-groups/m-p/13396929
 */

var settings = {
    templateLayerName: '_fixed obj',
    protectedLayerNames: ['_fixed obj', 'dima_var'],
    showResults: true,
};


(function () {

    if (app.documents.length == 0) {
        alert('Please open a document and try again.');
        return;
    }

    var doc = app.activeDocument,
        results = { __total: 0 };

    // get the template item layer
    try {
        var templateLayer = doc.layers.getByName(settings.templateLayerName);
    }
    catch (error) {
        alert('Could not find layer "' + settings.templateLayerName + '". Aborting.');
        return;
    }

    // collect template items
    var templateItems = [];

    for (var i = templateLayer.pageItems.length - 1; i >= 0; i--) {
        templateItems.push(templateLayer.pageItems[i]);

        // set up the results counters
        results[templateLayer.pageItems[i].name] = 0;
    }

    // take note of layer status
    var layers = [];
    for (var i = 0; i < doc.layers.length; i++) {
        var layer = doc.layers[i];

        if (indexOf(settings.protectedLayerNames, layer.name) != -1)
            continue;

        layers.push(
            {
                layer: layer,
                visible: layer.visible,
                locked: layer.locked,
            }
        );

        // show and unlock layer
        layer.visible = true;
        layer.locked = false;

    }

    // find clipping items with same name as templates
    for (var i = 0; i < doc.groupItems.length; i++) {

        var grp = doc.groupItems[i];

        for (var j = 0; j < templateItems.length; j++) {

            var templateItem = templateItems[j];

            if (
                grp.name != templateItem.name
                // || indexOf(settings.protectedLayerNames, grp.layer.name) != -1
            )
                continue;

            if (
                grp.clipped == true
                && grp.pathItems.length > 0
                && grp.pathItems[0].name == templateItem.name
                && grp.pathItems[0].clipping == true
            ) {

                var hidden = grp.hidden,
                    locked = grp.locked;

                grp.hidden = false;
                grp.locked = false;

                // duplicate the templateItem into the group
                var dup = templateItem.duplicate();
                dup.move(grp.pathItems[0], ElementPlacement.PLACEAFTER);
                dup.selected = false;

                grp.hidden = hidden;
                grp.locked = locked;

                results[templateItem.name]++;
                results.__total++;

            }

        }

    }

    // reset layer visibility
    for (var i = 0; i < layers.length; i++) {
        $/*debug*/.writeln('setting layer ' + i + ' "' + layers[i].layer.name + '" visible = ' + layers[i].visible);
        layers[i].layer.visible = layers[i].visible;
        layers[i].layer.locked = layers[i].locked;
    }

    templateLayer.remove();

    // show results
    if (settings.showResults) {

        var resultsMessage = 'Results:\n';

        for (var i = 0; i < templateItems.length; i++)
            resultsMessage += templateItems[i].name + ': ' + results[templateItems[i].name] + '\n';


        resultsMessage += '\nTotal : ' + results.__total;
        alert(resultsMessage);
    }


    // helper function
    function indexOf(array, obj) {
        for (var i = 0; i < array.length; i++)
            if (array[i] == obj)
                return i;
        return -1;
    };


})();

 

 

Edit 1: added handling for hidden and locked layers and group items.

Edit 2: fixed bugs introduced in edit 1! Also added show results setting.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 06, 2022 Dec 06, 2022

Copy link to clipboard

Copied

Thank you @m1b that's good! I'm trying to make it even more human-error-proof so that it works with all the layers, whether they are hidden or not, like the first script did. I tried different ways like deleting the code

grp.hidden !== true

or adding the code

&&grp.hidden !== false

 I also tried adding at the beginning this code:

app.executeMenuCommand('showAll'); 

but it just show the hidden sublayers of the already shown layers. I just want to get shown the hidden layers and stay the sublayers as they are.

Alternatively is there a way to make the script work with hidden layers too?

Thanks again!

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 06, 2022 Dec 06, 2022

Copy link to clipboard

Copied

I have updated script above. Please have another try. If you have more problems, it might be good to send through another test file that shows the problem. - Mark

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 06, 2022 Dec 06, 2022

Copy link to clipboard

Copied

Hi @m1b i tested the updated script, it works, now it applies the templates to all the layers may they be hidden or visible, but it does something a lil odd. 😉

Here's a new test file: test2 

I placed the template layer and more 4 layers (A, B, C, D)  in which the items have to be duplicated plus an hidden layer (dima_var) that has to not be touched by the script.

I made some tests (note: layer _fixed obj will be always visible):

 

- if at the beginning all layers are visible, after the script all layers are visible

- if at the beginning all layers are hidden, after the script only layer A is visible

- if at the beginning only layer A is visible, after the script only A and B will be visible.

- if at the beginning only layer B is visible, after the script only A and C will be visible

- if at the beginning only layer C is visible, after the script only A and D will be visible

- if at the beginning only layer D is visible, after the script only A and dima_var will be visible

- if at the beginning only layers B and C are visible, after the script only A, C, D be visible

 

It looks like it make visible the first layer and the one just below the hidden one...

I mean it's not a big problem but just to avoid confusion is it possible to have all the layers visible or hidden at the end?

Thanks!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 06, 2022 Dec 06, 2022

Copy link to clipboard

Copied

Yep, I messed up that last edit and didn't test properly. I've updated the script again and hopefully solved that problem. - Mark

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 07, 2022 Dec 07, 2022

Copy link to clipboard

Copied

Thank you @m1b i think we are almost there. If i want all layers to be visible regardless of their original status i guess i have to add this code:

var layers = app.activeDocument.layers;
for (var i = 0; i < layers.length; i++) {
  layers[i].visible = true;
}

but could you tell me what part of your code i have to replace? I tried different ways but i always got error.

Also, the alert with the counter at the end is a really nice touch and an "extra mile". It could help for sure but if i'd want to get rid of it to make the process more smooth what part of code should i remove?

Thank you again, after this i guess the script will be perfect and the post SOLVED!

 

Thansk, have a nice day!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 07, 2022 Dec 07, 2022

Copy link to clipboard

Copied

Hi @Magenta s.r.l.,

1. If you want to leave all the layers visible and unlocked, just comment out the loop under the comment "reset layer visibility". This part returns them to their original state.

2. If you don't want to see the results alert, just change to showResults: false in the settings object.

- Mark

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 07, 2022 Dec 07, 2022

Copy link to clipboard

Copied

That's it! Thank you, i think this is exactly what i wanted!

I appreciate your patiente and effort!

Have a nice day!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 07, 2022 Dec 07, 2022

Copy link to clipboard

Copied

Awesome! When you have the time, please look through the script carefully and try to understand each part. It will help your scripting capabilities. - Mark

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 07, 2022 Dec 07, 2022

Copy link to clipboard

Copied

LATEST

Yep, that's what i'm trying and i will take time to do it but right now time is shorter than my knowledge on the subject so yeah, i'm lucky to find helpful people like you!

Cheers!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines