SmartObjectLayer#

Class Reference SmartObjectLayer#

class psapi.SmartObjectLayer_8bit#

Smart objects are Photoshops’ way of non-destructive image data edits while keeping a live link to the original file.

We expose not only ways to replace this linked image data but also have functionality to recreate and store the warps applied to these objects (with more features coming in the future). We currently support recreating all the warps found in the Edit->Transform tab. We do not yet support the Edit->Puppet Warp and Edit->Perspective Warp which are stored as Smart Filters.

Smart objects store their original image data on the LayeredFile while storing a decoded preview the size of the layer on the layer itself. We provide multiple methods to get both the scaled and warped image data as well as the full size image data.

<b>Image Data:</b>

Due to how SmartObjects work, image data is read-only. In order to modify the underlying image data you should use the replace() method which will actually replace the underlying file the smart object is linked to.

Getting the image data can be done via the get_image_data(), get_channel_by_id(), get_channel_by_index() and get_original_image_data() functions. These will retrieve the transformed and warped image data. If you modify the transformations or the warp the warp is only redrawn on access to these functions.

<b>Transformations:</b>

Unlike normal layers, SmartObjects have slightly different transformation rules. As they link back to a file in memory or on disk the transformations are stored ‘live’ and can be modified without negatively impacting the quality of the image. We expose a variety of transformation options to allow you to express this freedom.

Since we have both the original image data, and the rescaled image data to worry about there is two different widths and heights available:

  • original_width() / original_height()

    These represent the resolution of the original file image data, irrespective of what transforms are applied to it. If you are e.g. loading a 4000x2000 jpeg these will return 4000 and 2000 respectively. These values may not be written to

  • width() / height()

    These represent the final dimensions of the SmartObject with the warp and any transformations applied to it.

For actually transforming the layer we expose the following methods:

  • move()

  • rotate()

  • scale()

  • transform()

These are all individually documented and abstract away the underlying implementation of these operations. You likely will not have to dive deeper than these.

<b>Warp:</b>

Smart objects can also store warps which we implement using the SmartObjectWarp structure. These warps are stored as bezier surfaces with transformations applied on top of them. The transformations should be disregarded by the user as we provide easier functions on the SmartObjectLayer directly (see above). You may transfer these warps from one layer to another, modify them (although this requires knowledge of how bezier surfaces work), or clear them entirely.

For the latter we provide the reset_transform()` and reset_warp() functions.

Attributes:
warpSmartObjectWarp

Property holding the warp (and transformation) information. May be modified, although for transforming the layer it is recommended to use the transformation functions such as move, rotate, scale and transform.

linkagepsapi.enum.LinkedLayerType

The linkage of the backing image file, if this is set to psapi.enum.LinkedLayerType.data the image is stored in the file while if it is set to psapi.enum.LinkedLayerType.external it links to the file on disk and only stores the transformed image on file.

namestr

The name of the layer, cannot be longer than 255

blend_modeenum.BlendMode

The blend mode of the layer, ‘Passthrough’ is reserved for group layers

opacityfloat

The layers opacity from 0.0 - 1.0

widthint

The width of the layer ranging up to 30,000 for PSD and 300,000 for PSB, this does not have to match the files width

heightint

The height of the layer ranging up to 30,000 for PSD and 300,000 for PSB, this does not have to match the files height

center_xfloat

The center of the layer in regards to the canvas, a layer at center_x = 0 is perfectly centered around the document

center_yfloat

The center of the layer in regards to the canvas, a layer at center_y = 0 is perfectly centered around the document

is_locked: bool

The locked state of the layer, this locks all pixel channels

is_visible: bool

Whether the layer is visible

mask: np.ndarray

The layers’ mask channel, may be empty

mask_disabled: bool

Whether the mask is disabled. Ignored if no mask is present

mask_relative_to_layer: bool

Whether the masks position is relative to the layer. Ignored if no mask is present

mask_default_color: int

The masks’ default color outside of the masks bounding box from 0-255. Ignored if no mask is present

mask_density: int

Optional mask density from 0-255, this is equivalent to layers’ opacity. Ignored if no mask is present

mask_feather: float

Optional mask feather. Ignored if no mask is present

mask_position: psapi.geometry.Point2D

The masks’ canvas coordinates, these represent the center of the mask in terms of the canvas (file). Ignored if no mask is present

mask_width: int

The masks’ width, this does not have to correspond with the layers’ width

mask_height: int

The masks’ height, this does not have to correspond with the layers’ height

__init__(self: psapi.SmartObjectLayer_8bit, layered_file: psapi.LayeredFile_8bit, path: str, layer_name: str, link_type: psapi.enum.LinkedLayerType = <LinkedLayerType.data: 0>, warp: Optional[PhotoshopAPI::SmartObject::Warp] = None, layer_mask: Optional[numpy.ndarray[numpy.uint8]] = None, blend_mode: psapi.enum.BlendMode = <BlendMode.normal: 1>, opacity: float = 1.0, compression: psapi.enum.Compression = <Compression.zipprediction: 3>, color_mode: psapi.enum.ColorMode = <ColorMode.rgb: 3>, is_visible: bool = True, is_locked: bool = False) None#

Construct a SmartObjectLayer from the given filepath, linking the layer according to the link type. Accepts an optional warp object to construct the layer with. If None is passed we default initialize the warp.

Parameters:
  • layered_file (LayeredFile_*bit) – The file into which the layer will be inserted. This needs to be present as the actual link to the image file is stored globally and not on the layer itself.

  • path (str) – The path to the image file to link into this SmartObject. This must be a valid file on disk.

  • layer_name (str) – The name of the group, its length must not exceed 255

  • layer_mask (numpy.ndarray) – Optional layer mask, must have the same dimensions as height * width as a 2-dimensional array with row-major ordering (for a numpy 2D array this would mean with a shape of (height, width)

  • blend_mode (psapi.enum.BlendMode) – Optional, the blend mode of the layer, ‘Passthrough’ is the default for groups.

  • opacity (int) – The opacity of the layer from 0-255 where 0 is 0% and 255 is 100%. Defaults to 255

  • compression (psapi.enum.Compression) – The compression to apply to all the channels of the layer, including mask channels

  • color_mode (psapi.enum.ColorMode) – The color mode of the Layer, this must be identical to the color mode of the document. Defaults to RGB

  • is_visible (bool) – Whether the group is visible

  • is_locked (bool) – Whether the group is locked

Raises:

ValueError: if length of layer name is greater than 255

ValueError: if opacity is not between 0-255

__getitem__(self: psapi.SmartObjectLayer_8bit, key: int) numpy.ndarray[numpy.uint8]#

Get the specified channel from the image data, this may also be the mask channel at index -2. If -2 is passed this function is identical to get_mask(). The mask channel will have the shape { mask_height(), mask_width() } while any other channel will have the shape { height(), width() }.

Generally accessing each channel individually is slower than accessing all of them with get_image_data() as that function is better parallelized. So if you wish to extract more than a couple channels it is recommended to get all of them.

raises ValueError:

if the specified index does not exist on the layer

Returns:

The extracted channel

Return type:

numpy.ndarray

channel_indices(self: psapi.SmartObjectLayer_8bit, include_mask: bool = True) List[int]#

Retrieve a list of all the channel indices.

param include_mask:

Whether to include the mask channel

filename(self: psapi.SmartObjectLayer_8bit) str#

Retrieve the filename associated with this smart object.

filepath(self: psapi.SmartObjectLayer_8bit) os.PathLike#
Retrieve the filepath associated with this smart object. Depending on how the

Smart object is linked (external or data) this may not be written to disk.

If the file is linked as data this path may not represent the actual filepath on disk as this information is no longer present.

get_channel_by_id(self: psapi.SmartObjectLayer_8bit, key: psapi.enum.ChannelID) numpy.ndarray[numpy.uint8]#
Get the specified channel from the image data, this may also be the mask channel at index -2.

If -2 is passed this function is identical to get_mask(). The mask channel will have the shape { mask_height(), mask_width() } while any other channel will have the shape { height(), width() }.

Generally accessing each channel individually is slower than accessing all of them with get_image_data() as that function is better parallelized. So if you wish to extract more than a couple channels it is recommended to get all of them.

param psapi.enum.ColorMode key:

The key to access.

raises ValueError:

if the specified index does not exist on the layer

Returns:

The extracted channel

Return type:

numpy.ndarray

get_channel_by_index(self: psapi.SmartObjectLayer_8bit, key: int) numpy.ndarray[numpy.uint8]#
Get the specified channel from the image data, this may also be the mask channel at index -2.

If -2 is passed this function is identical to get_mask(). The mask channel will have the shape { mask_height(), mask_width() } while any other channel will have the shape { height(), width() }.

Generally accessing each channel individually is slower than accessing all of them with get_image_data() as that function is better parallelized. So if you wish to extract more than a couple channels it is recommended to get all of them.

param int:

The key to access.

raises ValueError:

if the specified index does not exist on the layer

Returns:

The extracted channel

Return type:

numpy.ndarray

get_image_data(self: psapi.SmartObjectLayer_8bit) Dict[int, numpy.ndarray[numpy.uint8]]#
Get all the channels of the layer (including masks) as a dict mapped by intnp.ndarray. This includes

any mask channel which would be found at index -2. While all non-mask channels are guaranteed to be the same size as width() * height() this does not hold true for the mask channel which would be the size of mask_width() and mask_height()

Returns:

The extracted image data

Return type:

dict[int, numpy.ndarray]

get_original_image_data(self: psapi.SmartObjectLayer_8bit) Dict[int, numpy.ndarray[numpy.uint8]]#

Extract all the channels of the original image data.

Unlike the accessors get_image_data() and get_channel() this function gets the full resolution image data that is stored on the smart object, i.e. the original image data. This may be smaller or larger than the layers width or height. To get the actual resolution you can query: original_width() and original_height()

has_mask(self: psapi.Layer_8bit) bool#

Check whether the layer has an associated mask component (pixel mask)

hash(self: psapi.SmartObjectLayer_8bit) str#
Retrieve the hashed value associated with the layer, this is what is used to identify the

linked layer associated with this smart object (where the original image data is stored)

property mask#

The layers’ pixel mask, this is a 2-dimensional array stored in format { height, width }. A pixel mask may have any dimensions and does not have to match a layers’ width or height. To get the pixel value outside of the masks’ bbox use the mask_default_color property.

property mask_default_color#

The masks’ default color outside of the masks bounding box. Ignored if no mask is present. From 0-255 regardless of bit depth

property mask_density#

Optional mask density from 0-255, this is equivalent to layers’ opacity. Ignored if no mask is present

property mask_disabled#

Whether the mask is disabled. Ignored if no mask is present

property mask_feather#

Optional mask feather. Ignored if no mask is present

mask_height(self: psapi.Layer_8bit) int#

The masks’ height in pixels. This does not always have to correspond with the layers’ height.

property mask_position#

The masks’ canvas coordinates, these represent the center of the mask in terms of the canvas (file). Ignored if no mask is present

property mask_relative_to_layer#

Whether the masks position is relative to the layer. Ignored if no mask is present

mask_width(self: psapi.Layer_8bit) int#

The masks’ width in pixels. This does not always have to correspond with the layers’ width.

move(self: psapi.SmartObjectLayer_8bit, x_offset: float, y_offset: float) None#

Move the layer (including any warps) by the given x and y offset.

num_channels(self: psapi.SmartObjectLayer_8bit, include_mask: bool = True) int#

Retrieve the total number of channels held by the layer

param include_mask:

Whether to include the mask channel

original_height(self: psapi.SmartObjectLayer_8bit) int#

Retrieve the original image datas’ height.

This does not have the same limitation as Photoshop layers of being limited to 30,000 or 300,000 pixels depending on the file type

raises RuntimeError:

if the hash defined by hash() is not valid for the document

returns:

The height of the original image data

original_width(self: psapi.SmartObjectLayer_8bit) int#

Retrieve the original image datas’ width.

This does not have the same limitation as Photoshop layers of being limited to 30,000 or 300,000 pixels depending on the file type

raises RuntimeError:

if the hash defined by hash() is not valid for the document

returns:

The width of the original image data

replace(self: psapi.SmartObjectLayer_8bit, path: str, link_externally: bool = False) None#

Replace the smart object with the given path keeping transformations as well as warp in place.

Parameters:
  • path – The new filepath to link to, this must be a file format recognized both by Photoshop and OpenImageIO

  • link_externally

    Whether to link the file externally or store the raw file bytes on the

    photoshop document itself. Keeping this at its default False is recommended for sharing these files. If the file already exists as another smart object layer

    this parameter is ignored.

reset_transform(self: psapi.SmartObjectLayer_8bit) None#
Reset all the transformations (not the warp) applied to the layer to map it back to the original square

from [0 - original_width()] and [0 - original_height()]. This does not reset the warp itself so if

you had a warp applied it will stay.

If you instead wish to clear the warp you can use reset_warp().

These two may be used in combination and sequence, so it is perfectly valid to call reset_transform and reset_warp in any order.

reset_warp(self: psapi.SmartObjectLayer_8bit) None#

Reset the warp (not the transformations) applied to the Smart Object.

If you instead wish to clear the transformations you can use the reset_transform() function.

These two may be used in combination and sequence, so it is perfectly valid to call reset_transform and reset_warp in any order

rotate(self: psapi.SmartObjectLayer_8bit, angles: float, x: float, y: float) None#

Rotate the layer (including any warps) by the given angle (in degrees) around the point defined by the x and y coordinate. If you wish to rotate around the layers center you can call the function as follows:

layer.rotate(45, layer.center_x, layer.center_y)

Parameters:
  • angle – The angle to rotate with in degrees

  • x – The x position to rotate about

  • y – The y position to rotate about

scale(self: psapi.SmartObjectLayer_8bit, x_scalar: float, y_scalar: float, x: float, y: float) None#

Scale the layer (including any warps) by the given x and y scalar around the point defined by the x and y coordinate. If you wish to scale around the layers center you can call the function as follows:

layer.scale(1.0, 1.0, layer.center_x, layer.center_y)

Parameters:
  • x_scalar – The x component of the scalar

  • y_scalar – The y component of the scalar

  • x – The x position to scale about

  • y – The y position to scale about

set_mask_compression(self: psapi.Layer_8bit, arg0: psapi.enum.Compression) None#

Set the masks’ write compression in terms of one of the Photoshop compression codecs. The mask channel may have any compression codec applied to it and this does not need to match the layers’ compression in any way. All compression codecs are valid in the PhotoshopAPI.

transform(self: psapi.SmartObjectLayer_8bit, matrix: numpy.ndarray[numpy.float64]) None#

Apply the transformation matrix to the smart object layer. This must be a 3x3 matrix which can contain both affine and non affine transformations.

Parameters:

matrix (np.ndarray) – The matrix to transform by, as a 3x3 matrix of np.double