如何在具有已知名称的其他图层组内裁剪和导出特定图层组?

How do I crop and export specific group layers inside other group layers with a known name?

第一次post来这里!如果此 post 缺少信息,或者有碍观瞻,我事先表示歉意!

所以,我有一堆层,结构有点像这样的例子:

+ graphics (group, unique)
+ - + Figure_A (group, unique)
+ - + - + Figure_A_arm (group, unique)
+ - + - + - + Figure_A_arm_Variation1 (group, unique)
+ - + - + - + - + frame1_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)
+ - + - + - + - + frame2_arm (group, not unique)
+ - + - + - + - + - + FigureGraphic (linked layer, not unique, has a mask)

(unique/notunique表示图层名称是否唯一)

我正在尝试获取组层次结构中最新的像素,文档在自动导出之前被裁剪。主要问题是,有很多功能我无法弄清楚,即使在不停地戳了两个星期之后。我在脚本中挖掘了很多片段,但它变得一团糟,无法正常工作。 我在我想做的事情中包含了一个伪代码。理想情况下,我会编写其中编写的函数,但在谷歌搜索两周后,我无法弄清楚其中的很多内容。 Photoshop 脚本中的很多功能看起来很晦涩,我根本想不通...

我一直在通过从这些地方获取代码片段来编写函数:

导出为 PNG:Photoshop CS6 Export Nested Layers to PNG?

Select 所有子图层:http://www.joonas.me/posts/2018/01/30/select-child-layers-photoshop-script/

获取 selected 图层 ID:https://forums.adobe.com/thread/2256708

Select 图层按 ID:https://forums.adobe.com/thread/2140075

我一直在尝试,但我发现很难实现它们来做我需要的事情,有时我会收到错误或变量变成 'undefined',从而触发错误。

// Here's some 'pseudocode' with how I'm trying to make it work
cropAndSave("Figure_A_arm_Variation1");
cropAndSave("Figure_A_arm_Variation2");
cropAndSave("Figure_A_arm_Variation3");
cropAndSave("Figure_A_leg_Variation1");
cropAndSave("Figure_A_leg_Variation2");
cropAndSave("Figure_A_leg_Variation3");
cropAndSave("Figure_B_arm_Variation1");
cropAndSave("Figure_B_arm_Variation2");
cropAndSave("Figure_B_arm_Variation3");
//etc

function cropAndSave(nameOfGroup)
{
    //nameOfGroup is the group layer we are looking for

    //Duplicate the document so we don't mess with the original
    var workingDoc = app.activeDocument.duplicate();

    // Path we want to export to
    var path="C:/test/"+nameOfGroup+"/";

    // Look up for this group layer in the document
    setActiveLayerSet(nameOfGroup);

    // Make a list (array?) with the ids of each layer set/group inside nameOfGroup
    // This shouldn't include anything inside each group, only the direct groups inside nameOfGroup
    var listOfLayers = getListOfChildrenObjects();

    // Loop the process for each sub-object
    for( var i = 0; i < listOfLayers.length ; i++ )
    {
        var name = getLayerNameById(listOfLayers.i); //I don't know if this is the correct way to ask for the i element of a list
        var bounds = []; //We'll be using this for the cropping
        if(groupName=="Figure_A_arm_Variation1") //Checking which set we're doing
        {
            if(name=="frame1_arm") bounds = [1px, 2px, 3px, 4px]; //just a test value
            else if(name=="frame2_arm") bounds = [5px, 6px, 7px, 8px]; //just a test value
            else if(name=="frame3_arm") bounds = [9px, 10px, 11px, 12px]; //just a test value
            else if(name=="frame1_leg") bounds = [13px, 14px, 15px, 16px]; //just a test value
            // and so on
        }
        else if(groupName=="Figure_B_arm_Variation2") //one of the many possible groups
        {
            if(name=="frame1_arm") bounds = [17px, 18px, 19px, 20px];
            //etc
        }
        // Duplicate this since we will be doing more drastic changes
        var secondaryDoc = workingDoc.duplicate();

        // Select the layer we're working with
        selectLayerByID(listOfLayers.i);

        // Do the cropping
        if(bounds.length > 2) secondaryDoc.crop(bounds); //Each bounds array has 4 elements, check if that's the case to make sure we haven't input any weird values, then crop
        else alert('No bounds set up for layer '+name+' in group '+groupName); //in this case it should be cancelled but I'm not sure how to stop the script from executing

        // Condense the group 'name', which is the one we're working with, into a single layer for easier management
        condenseGroup();

        // Remove all the layers that aren't the one we're working with
        deleteAllLayersAndGroupsExceptSelected();

        // Save as PNG
        var pngFile = new File(path+name);
        pngSaveOptions = new PNGSaveOptions();
        pngSaveOptions.embedColorProfile = true;
        pngSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
        pngSaveOptions.matte = MatteType.NONE; pngSaveOptions.quality = 1;
        activeDocument.saveAs(pngFile, pngSaveOptions, false, Extension.LOWERCASE);

        // Close this duplicate without saving the PSD
        secondaryDoc.close(SaveOptions.DONOTSAVECHANGES);
    }
    workingDoc.close(SaveOptions.DONOTSAVECHANGES); 
}

所以我想摆脱它的是,在具有特定组结构的同时,使它 select 成为层次结构中的一个组,然后将每个子组的内容保存为 PNG将文档裁剪成一组尺寸,但我很难找到正确的方法和功能来完成它。

[编辑] 请求的图像在此处 post 编辑:

这是Layer structure。每个 "Figure_X_bodypart_VariationY" 中都有一组子组。我想通过将文档裁剪到为每个子组编码到脚本中的特定范围来处理这些子组中的每一个。

I have the PSD structured like this, the open folder has a mask, (which is the current selection to show which pixels belong to that layer). I want the script to select a rectangle specified for that one layer, like this.

在那之后,我希望脚本复制文档(这样它就不会弄乱原来的文档),然后crop using the bounds I've given in the script for that group. After that, the script should remove all the other groups so only this one remains,并将其另存为 PNG,然后关闭复制的文档,然后继续下一个子对象。

完成所有子对象后,继续每个 "Figure_X_bodypart_VariationY" 类型组

输入:

输出:

var exportPath = "/C/test-export",
    bounds = {
        child1: [
            44,
            92,
            338,
            363
        ],
        child2: [
            263,
            62,
            536,
            315
        ],
        child3: [
            160,
            269,
            458,
            497
        ]
    };

cropAndExport("figureA");

function cropAndExport(groupName)
{
    var doc = activeDocument;

    var masterClone = cloneDoc(); // master clone of the document

    masterClone.activeLayer = masterClone.layers.getByName(groupName); // selecting a group by name
    var groupChildren = masterClone.activeLayer.layers; // getting children of the group

    for (var i = 0; i < groupChildren.length; i++)
    {
        masterClone.activeLayer = groupChildren[i];
        var clone = cloneDoc();
        mergeDown(); // merging the group
        toggleVisibility(); //hiding all the other groupChildren
        rectSelection(bounds[groupChildren[i].name]); //you can use ifs to load bounds you want here, like if (groupChildren[i].name == 'child1') rectSelection(boundChild1);
        cropToSelection()
        savePng24(groupName, groupChildren[i].name, exportPath)
        clone.close(SaveOptions.DONOTSAVECHANGES);
    };

    masterClone.close(SaveOptions.DONOTSAVECHANGES);

    /////////////////////////////////////////////////////////////////////////////////////
    // functions
    /////////////////////////////////////////////////////////////////////////////////////

    function savePng24(nameX, nameY, exportFolder)
    {
        var pngOpts = new ExportOptionsSaveForWeb;
        pngOpts.format = SaveDocumentType.PNG
        pngOpts.PNG8 = false;
        pngOpts.transparency = true;
        activeDocument.exportDocument(new File(exportFolder + "/" + nameX + "_" + nameY + ".png"), ExportType.SAVEFORWEB, pngOpts);
    }; // end of savePng24()

    function cloneDoc()
    {
        var desc2 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Frst'));
        desc2.putReference(cTID('null'), ref1);
        desc2.putString(cTID('Nm  '), 'clone');
        executeAction(cTID('Dplc'), desc2, DialogModes.NO);
        return activeDocument;
    }; // end of cloneDoc()

    function mergeDown()
    {
        var desc11 = new ActionDescriptor();
        executeAction(cTID('Mrg2'), desc11, DialogModes.NO);
    }; // end of mergeDown()

    function toggleVisibility()
    {
        var desc102 = new ActionDescriptor();
        var list5 = new ActionList();
        var ref18 = new ActionReference();
        ref18.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
        list5.putReference(ref18);
        desc102.putList(cTID('null'), list5);
        desc102.putBoolean(cTID('TglO'), true);
        executeAction(cTID('Shw '), desc102, DialogModes.NO);
    }; // end of toggleVisibility()

    function rectSelection(data)
    {
        var desc25 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putProperty(cTID('Chnl'), cTID('fsel'));
        desc25.putReference(cTID('null'), ref1);
        var desc26 = new ActionDescriptor();
        desc26.putUnitDouble(cTID('Left'), cTID('#Pxl'), data[0]);
        desc26.putUnitDouble(cTID('Top '), cTID('#Pxl'), data[1]);
        desc26.putUnitDouble(cTID('Rght'), cTID('#Pxl'), data[2]);
        desc26.putUnitDouble(cTID('Btom'), cTID('#Pxl'), data[3]);
        desc25.putObject(cTID('T   '), cTID('Rctn'), desc26);
        executeAction(cTID('setd'), desc25, DialogModes.NO);
    }; // end of rectSelection()

    function cropToSelection()
    {
        var desc33 = new ActionDescriptor();
        desc33.putBoolean(cTID('Dlt '), true);
        executeAction(cTID('Crop'), desc33, DialogModes.NO);
    }; // end of cropToSelection()


    function cTID(s)
    {
        return app.charIDToTypeID(s);
    };

    function sTID(s)
    {
        return app.stringIDToTypeID(s);
    };


}