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 photoshoppsdimage – The target psdimage the image will be converted for.
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 or parent is None
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.