psd_tools.api.layers
Layer module.
This module implements the high-level layer API for psd-tools, providing Pythonic interfaces for working with Photoshop layers. It defines the layer type hierarchy and common operations.
Key classes:
Layer: Base class for all layer typesGroupMixin: Mixin for layers that contain children (groups, documents)Group: Folder/group layer containing other layersPixelLayer: Regular raster layer with pixel dataTypeLayer: Text layer with typography informationShapeLayer: Vector shape layerSmartObjectLayer: Embedded or linked smart objectAdjustmentLayer: Non-destructive adjustment (curves, levels, etc.)
Layer hierarchy:
Layers are organized in a tree structure where groups can contain child layers.
The GroupMixin provides iteration, indexing, and search capabilities:
# Iterate through all layers
for layer in psd:
print(layer.name)
# Access by index
first_layer = psd[0]
# Check if layer is a specific type
if layer.kind == 'pixel':
pixels = layer.numpy()
Common layer properties:
name: Layer namevisible: Visibility flagopacity: Opacity (0-255)blend_mode: Blend mode enumbbox: Bounding box (left, top, right, bottom)width,height: Dimensionskind: Layer type string (‘pixel’, ‘group’, ‘type’, etc.)parent: Parent layer or document
Layer operations:
composite(): Render layer to PIL Imagenumpy(): Get pixel data as NumPy arraytopil(): Convert to PIL Imagehas_mask(): Check if layer has a maskhas_clip_layers(): Check if layer has clipping mask
Example usage:
from psd_tools import PSDImage
psd = PSDImage.open('document.psd')
# Access first layer
layer = psd[0]
# Modify layer properties
layer.visible = False
layer.opacity = 128
layer.name = "New Name"
# Get pixel data
pixels = layer.numpy() # NumPy array
image = layer.topil() # PIL Image
# Work with groups
for group in psd.descendants():
if group.kind == 'group':
print(f"Group: {group.name} with {len(group)} layers")
# Composite specific layer
rendered = layer.composite()
rendered.save('layer.png')
Layer types are automatically determined from the underlying PSD structures
and exposed through the kind property for easy type checking.
Layer
- class psd_tools.api.layers.Layer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)[source]
- property bbox: tuple[int, int, int, int]
(left, top, right, bottom) tuple.
- property blend_mode: BlendMode
Blend mode of this layer. Writable.
Example:
from psd_tools.constants import BlendMode if layer.blend_mode == BlendMode.NORMAL: layer.blend_mode = BlendMode.SCREEN
- Returns:
- property bottom: int
Bottom coordinate.
- Returns:
int
- property clip_layers: list[Self]
Clip layers associated with this layer.
- Returns:
list of layers
- property clipping: bool
Clipping flag for this layer. Writable.
- Returns:
bool
- property clipping_layer: bool
Deprecated. Use clipping property instead.
- composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, apply_icc: bool = True) Image | None[source]
Composite layer and masks (mask, vector mask, and clipping layers).
- Parameters:
viewport – Viewport bounding box specified by (x1, y1, x2, y2) tuple. Default is the layer’s bbox.
force – Boolean flag to force vector drawing.
color – Backdrop color specified by scalar or tuple of scalar. The color value should be in [0.0, 1.0]. For example, (1., 0., 0.) specifies red in RGB color mode.
alpha – Backdrop alpha in [0.0, 1.0].
layer_filter – Callable that takes a layer as argument and returns whether if the layer is composited. Default is
is_visible().
- Returns:
PIL.Image.Imageor None.
- create_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) Mask[source]
Create a pixel mask on this layer from a PIL Image.
If the image has an alpha channel (e.g. RGBA, LA), the alpha channel is used as the mask data. Otherwise the image is converted to grayscale (
Lmode). White (255) means fully unmasked, black (0) means fully masked.- Parameters:
image – Source
Imagefor the mask.top – Top offset of the mask. Defaults to the layer’s top.
left – Left offset of the mask. Defaults to the layer’s left.
compression – Compression algorithm for the mask data.
- Returns:
The new
Mask.- Raises:
ValueError – If the layer already has a mask.
- property fill_opacity: int
Fill opacity of this layer in [0, 255] range. Writable.
- Returns:
int
- has_clip_layers(visible: bool = False) bool[source]
Returns True if the layer has associated clipping.
- Parameters:
visible – If True, check for visible clipping layers.
- Returns:
bool
- has_effects(enabled: bool = True, name: str | None = None) bool[source]
Returns True if the layer has effects.
- Parameters:
enabled – If True, check for enabled effects.
name – If given, check for specific effect type.
- Returns:
bool
- has_pixels() bool[source]
Returns True if the layer has associated pixels. When this is True, topil method returns
PIL.Image.Image.- Returns:
bool
- property height: int
Height of the layer.
- Returns:
int
- property kind: str
Kind of this layer, such as group, pixel, shape, type, smartobject, or psdimage. Class name without layer suffix.
- Returns:
str
- property layer_id: int
Layer ID.
- Returns:
int layer id. if the layer is not assigned an id, -1.
- property left: int
Left coordinate. Writable.
- Returns:
int
- lock(lock_flags: int = ProtectedFlags.COMPLETE) None[source]
Locks a layer accordind to the combination of flags.
- Parameters:
lockflags – An integer representing the locking state
Example using the constants of ProtectedFlags and bitwise or operation to lock both pixels and positions:
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)
- move_down(offset: int = 1) Self[source]
Moves the layer down a certain offset within the group the layer is in.
- Parameters:
offset – The number of positions to move the layer down (can be negative).
- Raises:
ValueError – If layer has no parent or parent is not a group
IndexError – If the new index is out of bounds
- Returns:
self
- move_to_group(group: GroupMixin) Self[source]
Deprecated: Use group.append(layer) instead.
- Parameters:
group – The group the current layer will be moved into.
- move_up(offset: int = 1) Self[source]
Moves the layer up a certain offset within the group the layer is in.
- Parameters:
offset – The number of positions to move the layer up (can be negative).
- Raises:
ValueError – If layer has no parent or parent is not a group
IndexError – If the new index is out of bounds
- Returns:
self
- property name: str
Layer name. Writable.
- Returns:
str
- numpy(channel: str | None = None, real_mask: bool = True) ndarray | None[source]
Get NumPy array of the layer.
- Parameters:
channel – Which channel to return, can be ‘color’, ‘shape’, ‘alpha’, or ‘mask’. Default is ‘color+alpha’.
- Returns:
numpy.ndarrayor None if there is no pixel.
- property offset: tuple[int, int]
(left, top) tuple. Writable.
- Returns:
tuple
- property opacity: int
Opacity of this layer in [0, 255] range. Writable.
- Returns:
int
- property origination: list[Origination]
Property for a list of live shapes or a line.
Some of the vector masks have associated live shape properties, that are Photoshop feature to handle primitive shapes such as a rectangle, an ellipse, or a line. Vector masks without live shape properties are plain path objects.
See
psd_tools.api.shape.- Returns:
List of
Invalidated,Rectangle,RoundedRectangle,Ellipse, orLine.
- property parent: GroupMixinProtocol | None
Parent of this layer.
- property reference_point: tuple[float, float]
Reference point of this layer as (x, y) tuple in the canvas coordinates. Writable.
Reference point is used for transformations such as rotation and scaling.
- Returns:
(x, y) tuple
- remove_mask() None[source]
Remove the pixel mask from this layer.
- Raises:
ValueError – If the layer does not have a mask.
- property right: int
Right coordinate.
- Returns:
int
- property sheet_color: SheetColorType
Color label of this layer in the Photoshop layers panel. Writable.
- Returns:
SheetColorType
- property size: tuple[int, int]
(width, height) tuple.
- Returns:
tuple
- property tagged_blocks: TaggedBlocks
Layer tagged blocks that is a dict-like container of settings.
See
psd_tools.constants.Tagfor available keys.- Returns:
Example:
from psd_tools.constants import Tag metadata = layer.tagged_blocks.get_data(Tag.METADATA_SETTING)
- property top: int
Top coordinate. Writable.
- Returns:
int
- topil(channel: int | None = None, apply_icc: bool = True) Image | None[source]
Get PIL Image of the layer.
- Parameters:
channel – Which channel to return; e.g., 0 for ‘R’ channel in RGB image. See
ChannelID. When None, the method returns all the channels supported by PIL modes.apply_icc – Whether to apply ICC profile conversion to sRGB.
- Returns:
PIL.Image.Image, or None if the layer has no pixels.
Example:
from psd_tools.constants import ChannelID image = layer.topil() red = layer.topil(ChannelID.CHANNEL_0) alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)
Note
Not all of the PSD image modes are supported in
PIL.Image.Image. For example, ‘CMYK’ mode cannot include alpha channel in PIL. In this case, topil drops alpha channel.
- update_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) Mask[source]
Update the pixel mask of this layer with a new image.
If the image has an alpha channel (e.g. RGBA, LA), the alpha channel is used as the mask data. Otherwise the image is converted to grayscale (
Lmode). White (255) means fully unmasked, black (0) means fully masked.- Parameters:
image – New source
Imagefor the mask.top – New top offset of the mask. Defaults to current mask top.
left – New left offset of the mask. Defaults to current mask left.
compression – Compression algorithm for the mask data.
- Returns:
The updated
Mask.- Raises:
ValueError – If the layer does not have a mask.
- property vector_mask: VectorMask | None
Returns vector mask associated with this layer.
- Returns:
VectorMaskor None
- property visible: bool
Layer visibility. Doesn’t take group visibility in account. Writable.
- Returns:
bool
- property width: int
Width of the layer.
- Returns:
int
Artboard
- class psd_tools.api.layers.Artboard(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)[source]
Artboard is a special kind of group that has a pre-defined viewbox.
- property bbox: tuple[int, int, int, int]
(left, top, right, bottom) tuple.
- property bottom: int
Bottom coordinate (computed from children, read-only).
- property left: int
Left coordinate (computed from children, read-only).
- property right: int
Right coordinate (computed from children, read-only).
- property top: int
Top coordinate (computed from children, read-only).
Group
- class psd_tools.api.layers.Group(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)[source]
Group of layers.
Example:
group = psd[1] for layer in group: if layer.kind == 'pixel': print(layer.name)
- property bottom: int
Bottom coordinate (computed from children, read-only).
- property clipping: bool
Clipping flag for this layer. Writable.
- Returns:
bool
- composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, apply_icc: bool = True) Image | None[source]
Composite layer and masks (mask, vector mask, and clipping layers).
- Parameters:
viewport – Viewport bounding box specified by (x1, y1, x2, y2) tuple. Default is the layer’s bbox.
force – Boolean flag to force vector drawing.
color – Backdrop color specified by scalar or tuple of scalar. The color value should be in [0.0, 1.0]. For example, (1., 0., 0.) specifies red in RGB color mode.
alpha – Backdrop alpha in [0.0, 1.0].
layer_filter – Callable that takes a layer as argument and returns whether if the layer is composited. Default is
is_visible().
- Returns:
PIL.Image.Image.
- static extract_bbox(layers: Sequence[Layer] | GroupMixin, include_invisible: bool = False, include_clipping: bool = False) tuple[int, int, int, int][source]
Returns a bounding box for
layersor (0, 0, 0, 0) if the layers have no bounding box.- Parameters:
layers – sequence of layers or a group.
include_invisible – include invisible layers in calculation.
include_clipping – include clipping layers in calculation. Defaults to False to match visible pixel bounds.
- Returns:
tuple of four int
- classmethod group_layers(parent: GroupMixin, layers: Sequence[Layer], name: str = 'Group', open_folder: bool = True) Self[source]
Deprecated: Use
psdimage.create_group(layer_list, name)instead.- Parameters:
parent – The parent group to add the newly created Group object into.
layers – The layers to group. Can by any subclass of
Layername – The display name of the group. Default to “Group”.
open_folder – Boolean defining whether the folder will be open or closed in photoshop. Default to True.
- Returns:
A
Group- Raises:
ValueError – If layers is empty
- property left: int
Left coordinate (computed from children, read-only).
- classmethod new(parent: GroupMixin, name: str = 'Group', open_folder: bool = True) Self[source]
Create a new Group object with minimal records and data channels and metadata to properly include the group in the PSD file.
- Parameters:
name – The display name of the group. Default to “Group”.
open_folder – Boolean defining whether the folder will be open or closed in photoshop. Default to True.
parent – Optional parent folder to move the newly created group into.
- Returns:
A
Groupobject- Raises:
ValueError – If parent is None
- property open_folder: bool
Returns True if the group is an open folder.
- Returns:
bool
- property right: int
Right coordinate (computed from children, read-only).
- property top: int
Top coordinate (computed from children, read-only).
PixelLayer
- class psd_tools.api.layers.PixelLayer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)[source]
Layer that has rasterized image in pixels.
Example:
assert layer.kind == 'pixel': image = layer.composite() image.save('layer.png')
- classmethod frompil(image: Image, parent: GroupMixin, name: str = 'Layer', top: int = 0, left: int = 0, compression: Compression = Compression.RLE, **kwargs: Any) PixelLayer[source]
Create a PixelLayer from a PIL image for a given psd file.
- Parameters:
image – The
Imageobject to convert to photoshopparent – The parent group or PSDImage this layer belongs to.
name – The name of the layer. Defaults to “Layer”
top – Pixelwise offset from the top of the canvas for the new layer.
left – Pixelwise offset from the left of the canvas for the new layer.
compression – Compression algorithm to use for the data.
- Returns:
A
PixelLayerobject- Raises:
TypeError – If image is not a PIL Image
ValueError – If parent is None
Note
If the image has an alpha channel and the parent PSD mode supports layer transparency (e.g. RGBA, LA), the alpha is stored as the layer transparency channel and no extra mask is created. For PSD modes that do not carry a transparency band (e.g. RGB, CMYK), the alpha channel is instead stored as a pixel mask (
USER_LAYER_MASK).
ShapeLayer
- class psd_tools.api.layers.ShapeLayer(*args: Any)[source]
Layer that has drawing in vector mask.
- property bbox: tuple[int, int, int, int]
(left, top, right, bottom) tuple.
- property bottom: int
Bottom coordinate.
- Returns:
int
- property left: int
Left coordinate. Writable.
- Returns:
int
- property right: int
Right coordinate.
- Returns:
int
- property top: int
Top coordinate. Writable.
- Returns:
int
SmartObjectLayer
- class psd_tools.api.layers.SmartObjectLayer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)[source]
Layer that inserts external data.
Use
smart_objectattribute to get the external data. SeeSmartObject.Example:
import io if layer.smart_object.filetype == 'jpg': image = Image.open(io.BytesIO(layer.smart_object.data))
- property smart_object: SmartObject
Associated smart object.
- Returns:
TypeLayer
- class psd_tools.api.layers.TypeLayer(*args: Any)[source]
Layer that has text and styling information for fonts or paragraphs.
Text is accessible at
textproperty. Styling information for paragraphs is inengine_dict. Document styling information such as font list is isresource_dict.Currently, textual information is read-only.
Example:
if layer.kind == 'type': print(layer.text) print(layer.engine_dict['StyleRun']) # Extract font for each substring in the text. text = layer.engine_dict['Editor']['Text'].value fontset = layer.resource_dict['FontSet'] runlength = layer.engine_dict['StyleRun']['RunLengthArray'] rundata = layer.engine_dict['StyleRun']['RunArray'] index = 0 for length, style in zip(runlength, rundata): substring = text[index:index + length] stylesheet = style['StyleSheet']['StyleSheetData'] font = fontset[stylesheet['Font']] print('%r gets %s' % (substring, font)) index += length
- property font_names: list[str]
List of PostScript font names used in this text layer.
Convenience shortcut for:
[font.postscript_name for font in layer.typesetting.fonts]
- property text: str
Text in the layer. Read-only.
Note
New-line character in Photoshop is ‘\r’.
- property text_type: TextType | None
Text type. Read-only.
- Returns:
psd_tools.constants.TextType.POINTfor point type text(also known as character type)
psd_tools.constants.TextType.PARAGRAPHfor paragraph type text(also known as area type)
None if text type cannot be determined or information is unavailable
- property transform: tuple[float, float, float, float, float, float]
Matrix (xx, xy, yx, yy, tx, ty) applies affine transformation.
- property typesetting: TypeSetting
Structured typographic data.
Returns a
TypeSettingobject that provides Pythonic access to fonts, paragraphs, styled runs, and default styles without navigating raw engine data dicts.Example:
ts = layer.typesetting for paragraph in ts: print(paragraph.style.justification) for run in paragraph.runs: print(run.text, run.style.font_name, run.style.font_size)
See also:
engine_dict,resource_dictfor raw data.
- property warp: DescriptorBlock | None
Warp configuration.