Contributing
Development happens at github: bug tracker. Feel free to submit bug reports or pull requests. Attaching an erroneous PSD file makes the debugging process faster. Such PSD file might be added to the test suite.
The license is MIT.
Package design
The package consists of four major subpackages:
psd_tools.psd: subpackage that reads/writes low-level binarystructure of the PSD/PSB file. The core data structures are built around attrs classes that all implement read and write methods. Each data object tries to resemble the structure described in the specification. Although documented, the specification is far from complete and some are even inaccurate. When psd-tools finds unknown data structure, the package keeps such data as bytes in the parsed result.
psd_tools.api: User-facing API that implements variouseasy-to-use methods that manipulate low-level
psd_tools.psddata structures. This is the primary interface for most users.
psd_tools.composite: Rendering engine for layer compositing andblending. This subpackage implements blend modes, layer effects (drop shadows, strokes, etc.), and vector shape rasterization. It uses NumPy arrays for efficient pixel manipulation and includes optional dependencies (scipy, scikit-image, aggdraw) that must be installed via the
compositeextra.
psd_tools.compression: Image compression codecs for raw data,RLE (Run-Length Encoding), and ZIP compression. The RLE codec includes a Cython-optimized implementation (_rle.pyx) that falls back to pure Python if not compiled, providing significant performance improvements for large files.
In the future, it might be good to implement the Photoshop API on top of the existing psd-tools API.
Testing
In order to run tests, make sure PIL/Pillow is built with LittleCMS or LittleCMS2 support. For example, on Ubuntu, install the following packages:
apt-get install liblcms2-dev libjpeg-dev libfreetype6-dev zlib1g-dev
Then install psd-tools with development dependencies:
uv sync --group dev --extra composite
Finally, run tests:
uv run pytest
Documentation
Install documentation dependencies:
uv sync --group docs
Once installed, use Makefile:
make docs
Release Process
Releases are automated via GitHub Actions. Only maintainers with appropriate repository permissions can trigger releases. The following repository secrets must be configured:
RELEASE_WORKFLOW_TOKEN: a fine-grained PAT withcontents: write, required so that the tag pushed byauto-tag.ymltriggers the downstreamrelease.ymlworkflow (the defaultGITHUB_TOKENcannot do this).PYPI_USERNAME/PYPI_PASSWORD: PyPI credentials for publishing.
Decide the version number following PEP 440 based on the changes since the last release. The auto-tag workflow recognises these forms:
v1.2.3— standard releasev1.2.3a1,v1.2.3b1,v1.2.3rc1— pre-releases (alpha, beta, release candidate)v1.2.3.post1— post-release
Update the changelog: Review
git logsince the last tag and summarize changes indocs/changelog.rstunder the new version heading.Create a release PR: Create a branch named
release/<version>, where<version>is one of the supported version forms listed above (e.g.release/v1.15.0,release/v1.15.0rc1, orrelease/v1.15.0.post1), commit the changelog update (and any version bumps), and open a PR againstmain. Merge it once approved. The branch name is how the auto-tag workflow identifies the version to tag.Automated tagging and publishing: Merging the release PR triggers the
auto-tagworkflow, which tags the exact merge commit that landed onmain(usingmerge_commit_sha) and pushes the tag. This in turn triggers thereleaseworkflow, which:Builds wheels for all supported platforms (Linux, Windows, macOS including ARM)
Generates release notes from git commits since the previous tag
Creates a GitHub release with the auto-generated changelog
Publishes the package to PyPI
Verify the release:
Check the Actions tab for workflow status
Verify the release on GitHub
Confirm the package is available on PyPI
Acknowledgments
Great thanks to all the contributors.