Skip to content

Layers

src.helpers.layers.getLayer(name: str, group: Union[str, None, list[str], LayerContainerTypes, Iterable[LayerContainerTypes]] = None) -> Optional[ArtLayer]

Retrieve ArtLayer object from given name and group/group tree.

Parameters:

Name Type Description Default
name str

Name of the layer.

required
group str | None | list[str] | LayerContainerTypes | Iterable[LayerContainerTypes]

Parent group (name or object), or ordered list of groups (names, or first can be an object).

None

Returns:

Type Description
ArtLayer | None

Layer object requested

Source code in src\helpers\layers.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def getLayer(
    name: str,
    group: Union[str, None, list[str], LayerContainerTypes, Iterable[LayerContainerTypes]] = None
) -> Optional[ArtLayer]:
    """Retrieve ArtLayer object from given name and group/group tree.

    Args:
        name: Name of the layer.
        group: Parent group (name or object), or ordered list of groups (names, or first can be an object).

    Returns:
        Layer object requested
    """
    try:
        # LayerSet provided?
        if not group:
            # LayerSet not provided
            return APP.activeDocument.artLayers[name]
        elif isinstance(group, str):
            # LayerSet name given
            return APP.activeDocument.layerSets[group].artLayers[name]
        elif isinstance(group, LayerContainer):
            # LayerSet object given
            return group.artLayers[name]
        elif isinstance(group, (tuple, list)):
            # Tuple or list of LayerSets
            layer_set = APP.activeDocument
            for g in group:
                if isinstance(g, str):
                    # LayerSet name given
                    layer_set = layer_set.layerSets[g]
                elif isinstance(g, LayerContainer):
                    # LayerSet object given
                    layer_set = g
            return layer_set.artLayers[name]
        # ArtLayer can't be located
        raise OSError(f"ArtLayer invalid")
    except PS_EXCEPTIONS:
        # Layer couldn't be found
        if ENV.DEV_MODE:
            print(f'Layer "{name}" could not be found!')
            if group and isinstance(group, LayerSet):
                print(f"LayerSet reference used: {group.name}")
            elif group and isinstance(group, str):
                print(f"LayerSet reference used: {group}")
    return

src.helpers.layers.getLayerSet(name: str, group: Union[str, None, list[str], LayerContainerTypes, Iterable[LayerContainerTypes]] = None) -> Optional[LayerSet]

Retrieve layer group object.

Parameters:

Name Type Description Default
name str

Name of the group to look for.

required
group str | None | list[str] | LayerContainerTypes | Iterable[LayerContainerTypes]

Parent group (name or object), or ordered list of groups (names, or first can be an object).

None

Returns:

Type Description
LayerSet | None

Group object requested.

Source code in src\helpers\layers.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def getLayerSet(
    name: str,
    group: Union[str, None, list[str], LayerContainerTypes, Iterable[LayerContainerTypes]] = None
) -> Optional[LayerSet]:
    """Retrieve layer group object.

    Args:
        name: Name of the group to look for.
        group: Parent group (name or object), or ordered list of groups (names, or first can be an object).

    Returns:
        Group object requested.
    """
    try:
        # Was LayerSet provided?
        if not group:
            # No LayerSet given
            return APP.activeDocument.layerSets[name]
        elif isinstance(group, str):
            # LayerSet name given
            return APP.activeDocument.layerSets[group].layerSets[name]
        elif isinstance(group, (tuple, list)):
            # Tuple or list of groups
            layer_set = APP.activeDocument
            for g in group:
                if isinstance(g, str):
                    # LayerSet name given
                    layer_set = layer_set.layerSets[g]
                elif isinstance(g, LayerContainer):
                    # LayerSet object given
                    layer_set = g
            return layer_set.layerSets[name]
        elif isinstance(group, LayerContainer):
            # LayerSet object given
            return group.layerSets[name]
        # LayerSet can't be located
        raise OSError(f"LayerSet invalid")
    except PS_EXCEPTIONS:
        print(f'LayerSet "{name}" could not be found!')
        if group and isinstance(group, LayerSet):
            print(f"LayerSet reference used: {group.name}")
        elif group and isinstance(group, str):
            print(f"LayerSet reference used: {group}")
    return

src.helpers.layers.get_reference_layer(name: str, group: Union[None, str, LayerSet] = None) -> Optional[ReferenceLayer]

Get an ArtLayer that is a static reference layer.

Parameters:

Name Type Description Default
name str

Name of the reference layer.

required
group None | str | LayerSet

Name of a LayerSet or LayerSet object which contains the reference layer, if provided.

None
Notes

ReferenceLayer is a subclass of ArtLayer which includes supplemental features for caching and improving execution time on bounds and dimensions handling.

Source code in src\helpers\layers.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def get_reference_layer(name: str, group: Union[None, str, LayerSet] = None) -> Optional[ReferenceLayer]:
    """Get an ArtLayer that is a static reference layer.

    Args:
        name: Name of the reference layer.
        group: Name of a LayerSet or LayerSet object which contains the reference layer, if provided.

    Notes:
        ReferenceLayer is a subclass of ArtLayer which includes
            supplemental features for caching and improving execution
            time on bounds and dimensions handling.
    """

    # Select the proper group if str or None provided
    if not group:
        group = APP.activeDocument
    if isinstance(group, str):
        try:
            group = APP.activeDocument.layerSets[group]
        except PS_EXCEPTIONS:
            group = APP.activeDocument

    # Select the reference layer
    with suppress(Exception):
        return ReferenceLayer(
            parent=group.artLayers.app[name],
            app=APP)
    return None

src.helpers.layers.create_new_layer(layer_name: Optional[str] = None) -> ArtLayer

Creates a new layer below the currently active layer. The layer will be visible.

Parameters:

Name Type Description Default
layer_name str | None

Optional name for the new layer

None

Returns:

Type Description
ArtLayer

Newly created layer object

Source code in src\helpers\layers.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def create_new_layer(layer_name: Optional[str] = None) -> ArtLayer:
    """Creates a new layer below the currently active layer. The layer will be visible.

    Args:
        layer_name: Optional name for the new layer

    Returns:
        Newly created layer object
    """
    # Create new layer at top of layers
    active_layer = APP.activeDocument.activeLayer
    layer = APP.activeDocument.artLayers.add()
    layer.name = layer_name or "Layer"

    # Name it & set blend mode to normal
    layer.blendMode = BlendMode.NormalBlend

    # Move the layer below
    layer.moveAfter(active_layer)
    return layer

src.helpers.layers.merge_layers(layers: list[ArtLayer] = None, name: Optional[str] = None) -> ArtLayer

Merge a set of layers together.

Todo

Check if this can merge layer groups with layers.

Parameters:

Name Type Description Default
layers list[ArtLayer]

Layers to be merged, uses active if not provided.

None
name str | None

Name of the newly created layer.

None

Returns:

Type Description
ArtLayer

Returns the merged layer.

Source code in src\helpers\layers.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
def merge_layers(layers: list[ArtLayer] = None, name: Optional[str] = None) -> ArtLayer:
    """Merge a set of layers together.

    Todo:
        Check if this can merge layer groups with layers.

    Args:
        layers: Layers to be merged, uses active if not provided.
        name: Name of the newly created layer.

    Returns:
        Returns the merged layer.
    """

    # Return layer if only one is present in the list
    if len(layers) == 1:
        return layers[0]

    # Select none, then select entire list
    if layers:
        select_layers(layers)

    # Merge layers and return result
    APP.executeAction(sID("mergeLayersNew"), None, NO_DIALOG)
    if name:
        APP.activeDocument.activeLayer.name = name
    return APP.activeDocument.activeLayer

src.helpers.layers.group_layers(name: Optional[str] = 'New Group', layers: Optional[list[Union[ArtLayer, LayerSet]]] = None) -> LayerSet

Groups the selected layers.

Parameters:

Name Type Description Default
name str | None

Name of the new group.

'New Group'
layers list[ArtLayer | LayerSet] | None

Layers to group, will use active if not provided.

None

Returns:

Type Description
LayerSet

The newly created group.

Source code in src\helpers\layers.py
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
def group_layers(
    name: Optional[str] = "New Group",
    layers: Optional[list[Union[ArtLayer, LayerSet]]] = None,
) -> LayerSet:
    """Groups the selected layers.

    Args:
        name: Name of the new group.
        layers: Layers to group, will use active if not provided.

    Returns:
        The newly created group.
    """
    # Select layers if given
    if layers:
        select_layers(layers)

    # Group the layers
    desc1 = ActionDescriptor()
    ref1 = ActionReference()
    ref2 = ActionReference()
    ref1.putClass(sID("layerSection"))
    desc1.putReference(sID('null'), ref1)
    ref2.putEnumerated(cID('Lyr '), cID('Ordn'), cID('Trgt'))
    desc1.putReference(cID('From'), ref2)
    desc2 = ActionDescriptor()
    desc2.putString(cID('Nm  '), name)
    desc1.putObject(cID('Usng'), sID("layerSection"), desc2)
    desc1.putInteger(sID("layerSectionStart"), 0)
    desc1.putInteger(sID("layerSectionEnd"), 1)
    desc1.putString(cID('Nm  '), name)
    APP.executeAction(cID('Mk  '), desc1, NO_DIALOG)
    return APP.activeDocument.activeLayer

src.helpers.layers.duplicate_group(name: str) -> LayerSet

Duplicates current active layer set without renaming contents.

Parameters:

Name Type Description Default
name str

Name to give the newly created layer set.

required

Returns:

Type Description
LayerSet

The newly created layer set object.

Source code in src\helpers\layers.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def duplicate_group(name: str) -> LayerSet:
    """Duplicates current active layer set without renaming contents.

    Args:
        name: Name to give the newly created layer set.

    Returns:
        The newly created layer set object.
    """
    desc241 = ActionDescriptor()
    ref4 = ActionReference()
    ref4.putEnumerated(sID("layer"), sID("ordinal"), sID("targetEnum"))
    desc241.putReference(sID("target"),  ref4)
    desc241.putString(sID("name"), name)
    desc241.putInteger(sID("version"),  5)
    APP.executeAction(sID("duplicate"), desc241, NO_DIALOG)
    return APP.activeDocument.activeLayer

src.helpers.layers.merge_group(group: Optional[LayerSet] = None) -> None

Merges a layer set into a single layer.

Parameters:

Name Type Description Default
group LayerSet | None

Layer set to merge. Merges active if not provided.

None
Source code in src\helpers\layers.py
278
279
280
281
282
283
284
285
286
def merge_group(group: Optional[LayerSet] = None) -> None:
    """Merges a layer set into a single layer.

    Args:
        group: Layer set to merge. Merges active if not provided.
    """
    if group:
        APP.activeDocument.activeLayer = group
    APP.executeAction(sID("mergeLayersNew"), None, NO_DIALOG)

src.helpers.layers.smart_layer(layer: Union[ArtLayer, LayerSet] = None, docref: Optional[Document] = None) -> ArtLayer

Makes a given layer, or the currently selected layer(s) into a smart layer.

Parameters:

Name Type Description Default
layer ArtLayer | LayerSet

Layer to turn into smart layer, use active layer(s) if not provided.

None
docref Document | None

Document reference, use active if not provided.

None
Source code in src\helpers\layers.py
294
295
296
297
298
299
300
301
302
303
304
305
def smart_layer(layer: Union[ArtLayer, LayerSet] = None, docref: Optional[Document] = None) -> ArtLayer:
    """Makes a given layer, or the currently selected layer(s) into a smart layer.

    Args:
        layer: Layer to turn into smart layer, use active layer(s) if not provided.
        docref: Document reference, use active if not provided.
    """
    docref = docref or APP.activeDocument
    if layer:
        docref.activeLayer = layer
    APP.executeAction(sID("newPlacedLayer"), None, NO_DIALOG)
    return docref.activeLayer

src.helpers.layers.edit_smart_layer(layer: Optional[ArtLayer] = None, docref: Optional[Document] = None) -> None

Opens the contents of a given smart layer (as a separate document) for editing.

Parameters:

Name Type Description Default
layer ArtLayer | None

Smart layer to open for editing, use active if not provided.

None
docref Document | None

Document reference, use active if not provided.

None
Source code in src\helpers\layers.py
308
309
310
311
312
313
314
315
316
317
318
def edit_smart_layer(layer: Optional[ArtLayer] = None, docref: Optional[Document] = None) -> None:
    """Opens the contents of a given smart layer (as a separate document) for editing.

    Args:
        layer: Smart layer to open for editing, use active if not provided.
        docref: Document reference, use active if not provided.
    """
    if layer:
        docref = docref or APP.activeDocument
        docref.activeLayer = layer
    APP.executeAction(sID("placedLayerEditContents"), None, NO_DIALOG)

src.helpers.layers.unpack_smart_layer(layer: Optional[ArtLayer] = None, docref: Optional[Document] = None) -> None

Converts a smart layer back into its separate components.

Parameters:

Name Type Description Default
layer ArtLayer | None

Smart layer to unpack into regular layers, use active if not provided.

None
docref Document | None

Document reference, use active if not provided.

None
Source code in src\helpers\layers.py
321
322
323
324
325
326
327
328
329
330
331
def unpack_smart_layer(layer: Optional[ArtLayer] = None, docref: Optional[Document] = None) -> None:
    """Converts a smart layer back into its separate components.

    Args:
        layer: Smart layer to unpack into regular layers, use active if not provided.
        docref: Document reference, use active if not provided.
    """
    if layer:
        docref = docref or APP.activeDocument
        docref.activeLayer = layer
    APP.executeAction(sID("placedLayerConvertToLayers"), None, NO_DIALOG)

src.helpers.layers.lock_layer(layer: Union[ArtLayer, LayerSet], protection: str = 'protectAll') -> None

Locks the given layer.

Parameters:

Name Type Description Default
layer ArtLayer | LayerSet

The layer to lock.

required
protection str

protectAll to lock, protectNone to unlock

'protectAll'
Source code in src\helpers\layers.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
def lock_layer(layer: Union[ArtLayer, LayerSet], protection: str = "protectAll") -> None:
    """Locks the given layer.

    Args:
        layer: The layer to lock.
        protection: protectAll to lock, protectNone to unlock
    """
    d1 = ActionDescriptor()
    d2 = ActionDescriptor()
    r1 = ActionReference()
    r1.putIdentifier(sID("layer"), layer.id)
    d1.putReference(sID("target"), r1)
    d2.putBoolean(sID(protection), True)
    idlayerLocking = sID("layerLocking")
    d1.putObject(idlayerLocking, idlayerLocking, d2)
    APP.executeAction(sID("applyLocking"), d1, NO_DIALOG)

src.helpers.layers.unlock_layer(layer: Union[ArtLayer, LayerSet]) -> None

Unlocks the given layer.

Parameters:

Name Type Description Default
layer ArtLayer | LayerSet

The layer to unlock.

required
Source code in src\helpers\layers.py
357
358
359
360
361
362
363
def unlock_layer(layer: Union[ArtLayer, LayerSet]) -> None:
    """Unlocks the given layer.

    Args:
        layer: The layer to unlock.
    """
    lock_layer(layer, "protectNone")

src.helpers.layers.select_layer(layer: Union[ArtLayer, LayerSet], make_visible: bool = False) -> None

Select a layer and optionally make it visible.

Parameters:

Name Type Description Default
layer ArtLayer | LayerSet

Layer to select.

required
make_visible bool

Whether to force the layer to be visible.

False
Source code in src\helpers\layers.py
371
372
373
374
375
376
377
378
379
380
381
382
383
def select_layer(layer: Union[ArtLayer, LayerSet], make_visible: bool = False) -> None:
    """Select a layer and optionally make it visible.

    Args:
        layer: Layer to select.
        make_visible: Whether to force the layer to be visible.
    """
    d1 = ActionDescriptor()
    r1 = ActionReference()
    r1.putIdentifier(sID('layer'), layer.id)
    d1.putReference(sID('target'), r1)
    d1.putBoolean(sID('makeVisible'), make_visible)
    APP.executeAction(sID('select'), d1, NO_DIALOG)

src.helpers.layers.select_layer_add(layer: Union[ArtLayer, LayerSet], make_visible: bool = False) -> None

Add layer to currently selected and optionally force it to be visible.

Parameters:

Name Type Description Default
layer ArtLayer | LayerSet

Layer to select.

required
make_visible bool

Make the layer visible if not currently visible.

False
Source code in src\helpers\layers.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
def select_layer_add(
    layer: Union[ArtLayer, LayerSet],
    make_visible: bool = False
) -> None:
    """Add layer to currently selected and optionally force it to be visible.

    Args:
        layer: Layer to select.
        make_visible: Make the layer visible if not currently visible.
    """
    desc1 = ActionDescriptor()
    ref1 = ActionReference()
    ref1.putIdentifier(sID("layer"), layer.id)
    desc1.putReference(sID("target"), ref1)
    desc1.putEnumerated(
        sID('selectionModifier'),
        sID('selectionModifierType'),
        sID('addToSelection'))
    desc1.putBoolean(sID("makeVisible"), make_visible)
    APP.executeAction(sID('select'), desc1, NO_DIALOG)

src.helpers.layers.select_layers(layers: list[Union[ArtLayer, LayerSet]]) -> None

Makes a list of layers active (selected) in the layer panel.

Parameters:

Name Type Description Default
layers list[ArtLayer | LayerSet]

List of layers or layer sets.

required
Source code in src\helpers\layers.py
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
def select_layers(layers: list[Union[ArtLayer, LayerSet]]) -> None:
    """Makes a list of layers active (selected) in the layer panel.

    Args:
        layers: List of layers or layer sets.
    """
    # Select no layers
    if not layers:
        return
    if len(layers) == 1:
        APP.activeDocument.activeLayer = layers[0]
    select_no_layers()

    # ID's and descriptors
    idLayer = sID('layer')
    idSelect = sID('select')
    idTarget = sID('target')
    idAddToSel = sID('addToSelection')
    idSelMod = sID('selectionModifier')
    idSelModType = sID('selectionModifierType')
    d1, r1 = ActionDescriptor(), ActionReference()

    # Select initial layer
    r1.putIdentifier(idLayer, layers.pop().id)
    d1.putReference(idTarget, r1)
    d1.putEnumerated(idSelMod, idSelModType, idAddToSel)
    d1.putBoolean(sID('makeVisible'), False)
    APP.executeAction(idSelect, d1, NO_DIALOG)

    # Select each additional layer
    for lay in layers:
        r1.putIdentifier(idLayer, lay.id)
        d1.putReference(idTarget, r1)
        APP.executeAction(idSelect, d1, NO_DIALOG)

src.helpers.layers.select_no_layers() -> None

Deselect all layers.

Source code in src\helpers\layers.py
444
445
446
447
448
449
def select_no_layers() -> None:
    """Deselect all layers."""
    d1, r1 = ActionDescriptor(), ActionReference()
    r1.putEnumerated(sID("layer"), sID("ordinal"), sID("targetEnum"))
    d1.putReference(sID("target"), r1)
    APP.executeAction(sID("selectNoLayers"), d1, NO_DIALOG)