Migration Guide

v1.12

psd-tools 1.12 makes composite dependencies optional to support more platforms and Python versions.

Breaking Change: Optional Composite Dependencies

The main breaking change in version 1.12 is that advanced compositing features now require optional dependencies that must be explicitly installed.

What changed:

  • Dependencies aggdraw, scipy, and scikit-image are now optional

  • Basic compositing with NumPy continues to work without these dependencies

  • Advanced features (vector masks, gradients, patterns, effects) require the composite extra

Migration steps:

If you use advanced compositing features, install with the composite extra:

pip install 'psd-tools[composite]'

Or install the dependencies separately:

pip install psd-tools aggdraw scipy scikit-image

What works without composite dependencies:

  • Reading and writing PSD files

  • Accessing layer information (names, dimensions, etc.)

  • Extracting raw pixel data with NumPy

  • Basic pixel layer compositing

  • Using cached layer previews

What requires composite dependencies:

  • Vector shape and stroke rendering

  • Gradient fills

  • Pattern fills

  • Layer effects rendering (drop shadows, strokes, etc.)

Error handling:

If you try to use advanced features without the dependencies installed, you’ll see a clear error:

ImportError: Advanced compositing features require optional dependencies.
Install with: pip install 'psd-tools[composite]'

Why this change:

This change enables psd-tools to run on platforms where some composite dependencies are unavailable, particularly Python 3.14 on Windows where aggdraw is not yet available.

Module Structure Changes

Version 1.12 includes some internal refactoring that generally doesn’t affect public APIs:

  • The PSD class moved from psd_tools.psd to psd_tools.psd.document (still importable from psd_tools.psd)

  • Utils module split into registry and bin_utils (internal change)

  • Composite module reorganized for better type safety (internal change)

These changes maintain backward compatibility for public imports.

Type Annotations

Version 1.12 adds comprehensive type annotations throughout the codebase. If you use type checkers like mypy, you may discover type errors in your code that were previously undetected. This is a good thing - the annotations help catch bugs earlier!

v1.11

psd-tools 1.11 introduces stronger type-safety via annotation and new public APIs for layer creation. Now the following approach is possible to create a new layered document:

from PIL import Image
from psd_tools import PSDImage

image = Image.new("RGBA", (width, height))
psdimage = PSDImage.new(mode='RGB', size=(640, 480), depth=8)
layer = psdimage.create_pixel_layer(image, name="Layer 1", top=0, left=0, opacity=255)
psdimage.save('new_image.psd')

Version 1.11 introduces some breaking changes.

Layer creation now disables orphaned layers. They must be given a valid PSDImage object.

version 1.11.x:

image = Image.new("RGBA", (width, height))
psdimage.create_pixel_layer(psdimage, image)

version 1.10.x:

image = Image.new("RGBA", (width, height))
PixelLayer.frompil(None, image, parent=None)

The same layer cannot be shared between multiple container objects.

version 1.11.x:

layer = psdimage.create_pixel_layer(group, image)
psdimage.append(layer)  # This won't duplicate the layer.

v1.10

psd-tools 1.10 has a few breaking changes.

Basic layer structure editing is supported in 1.10. You can add or remove a pixel layer, or change the grouping of layers.

psd-tools 1.10 drops compose module. Use composite instead.

version 1.10.x:

image = psd.composite()
layer_image = layer.composite()

v1.9

psd-tools 1.9 switches to NumPy based compositing.

version 1.8.x:

psd = PSDImage.open(filename)
image = psd.compose()
layer = psd[0]
layer_image = layer.compose()

version 1.9.x:

psd = PSDImage.open(filename)
image = psd.composite()
layer = psd[0]
layer_image = layer.composite()

NumPy array API is introduced:

image = psd.numpy()
layer_image = layer.numpy()

v1.8

There are major API changes in version 1.8.x.

Note

In version 1.8.0 - 1.8.7, the package name was psd_tools2.

PSDImage

File open method is changed from load to open().

version 1.7.x:

psd = PSDImage.load(filename)
with open(filename, 'rb') as f:
    psd = PSDImage.from_stream(f)

version 1.8.x:

psd = PSDImage.open(filename)
with open(filename, 'rb') as f:
    psd = PSDImage.open(f)

Layers

Children of PSDImage or Group is directly accessible by iterator or indexing.

version 1.7.x:

for layer in group.layers:
    print(layer)

first_child = group.layers[0]

version 1.8.x:

for layer in group:
    print(layer)

first_child = group[0]

In version 1.8.x, the order of layers is reversed to reflect that the index should not change when a new layer is added on top.

PIL export

Primary PIL export method is compose().

version 1.7.x:

image = psd.as_PIL()

layer_image = compose(layer)
raw_layer_image = layer.as_PIL()

version 1.8.x:

image = psd.compose()

layer_image = layer.compose()
raw_layer_image = layer.topil()

Low-level data structure

Data structures are completely rewritten to support writing functionality. See psd_tools.psd subpackage.

version 1.7.x:

psd.decoded_data

version 1.8.x:

psd._record

Drop pymaging support

Pymaging support is dropped.