Why yet another PSD reader?

PSD reader in PIL is incomplete and contributing to PIL
is complicated because of the slow release process, but the main issue
with PIL for me is that PIL doesn’t have an API for layer groups.

GIMP is cool, but it is a huge dependency, its PSD parser
is not perfect and it is not easy to use GIMP Python plugin
from your code.

I also considered contributing to pypsd or psdparse, but they are
GPL and I was not totally satisfied with the interface and the code
(they are really fine, that’s me having specific style requirements).

So I finally decided to roll out yet another implementation
that should be MIT-licensed, systematically based on the specification
(it turns out the specs are incomplete and sometimes incorrect though);
parser should be implemented as a set of functions; the package should
have tests and support both Python 2.x and Python 3.x.

Design overview

The process of handling a PSD file is split into 3 stages:

“Reading”: the file is read and parsed to low-level data
structures that closely match the specification. No user-accessible
images are constructed; image resources blocks and additional layer
information are extracted but not parsed (they remain just keys
with a binary data). The goal is to extract all information
from a PSD file.

“Decoding”: image resource blocks and additional layer
information blocks are parsed to a more detailed data structures
(that are still based on a specification). There are a lot of PSD
data types and the library currently doesn’t handle them all, but
it should be easy to add the parsing code for the missing PSD data
structures if needed.

After (1) and (2) we have an in-memory data structure that closely
resembles PSD file; it should be fairly complete but very low-level
and not easy to use. So there is a third stage:

Stage separation also means user-facing API may be opinionated:
if somebody doesn’t like it then it should possible to build an
another API based on lower-level decoded PSD file.

psd-tools tries not to throw away information from the original
PSD file; even if the library can’t parse some info, this info
will be likely available somewhere as raw bytes (open a bug if this is
not the case). This should make it possible to modify and write PSD
files (currently not implemented; contributions are welcome).

Features

Supported:

reading of RGB, RGBA, CMYK, CMYKA and Grayscale images;

8bit, 16bit and 32bit channels;

all PSD compression methods are supported (not only the most
common RAW and RLE);

image ICC profile is taken into account;

many image resource types and tagged block types are decoded;

layer effects information is decoded;

Descriptor structures are decoded;

there is an optional Cython extension to make the parsing fast;

very basic & experimental layer merging.

Not implemented:

reading of Duotone, LAB, etc. images;

many image resource types and tagged blocks are not decoded
(they are attached to the result as raw bytes);

some of the raw Descriptor values (like EngineData) are not decoded;

this library can’t reliably blend layers together: it is possible to export
a single layer and to export a final image, but rendering of
e.g. layer group may produce incorrect results;

the writing of PSD images is not implemented;

Pymaging support is limited: it only supports 8bit RGB/RGBA
images, ICC profiles are not applied, layer merging doesn’t work, etc.

If you need some of unimplemented features then please fire an issue
or implement it yourself (pull requests are welcome in this case).

0.8 (2013-02-26)

0.7.1 (2012-12-27)

Typo is fixed: LayerRecord.cilpping should be LayerRecord.clipping.
Thanks Oliver Zheng.

0.7 (2012-11-08)

Highly experimental: basic layer merging is implemented
(e.g. it is now possible to export layer group to a PIL image);

Layer.visible no longer takes group visibility in account;

Layer.visible_global is the old Layer.visible;

psd_tools.user_api.combined_bbox made public;

Layer.width and Layer.height are removed (use layer.bbox.width
and layer.bbox.height instead);

pil_support.composite_image_to_PIL is renamed to pil_support.extract_composite_image and
pil_support.layer_to_PIL is renamed to pil_support.extract_layer_image
in order to have the same API for pil_support and pymaging_support.