Recently encountered a business need to implement PSD file parsing layer function according to the PSD file, found a Python library to parse PSD. The library is PSD-Tools, which is a Python package for working with Adobe Photoshop PSD files. The following is a basic introduction to PSD-Tools.

The characteristics of

Support:

  • Read and write primary PSD/PSB file structures
  • Export the original layer image in NumPy and PIL format

Limited support:

  • Construction of a base layer based on pixels
  • Fill layer effect construction
  • The vector mask
  • Edit some layer properties, such as the layer name
  • Mixing mode except dissolution
  • Plot bezier curves

Does not support:

  • Edit the layer structure, such as adding or removing a layer
  • Adjust the structure of the layers
  • Many layers of effect construction
  • Font rendering

The installation

Use PIP to install the package.

pip install psd-tools 
Copy the code

For full layer image composition functionality, you can also install NumPy/SciPy:

pip install numpy scipy
Copy the code

use

Simple example

from psd_tools import PSDImage

psd = PSDImage.open('example.psd')
psd.composite().save('example.png')

for layer in psd:
    print(layer)
    layer_image = layer.composite()
    layer_image.save('%s.png' % layer.name)
Copy the code

The command line

The package provides command-line tools to process PSD files.

psd-tools export <input_file> <output_file> [options] psd-tools show <input_file> [options] psd-tools debug <input_file>  [options] psd-tools -h | --help
psd-tools --version
Copy the code

Example:

PSD -tools export example.psd example.png # PSD -tools export example.psd0] example-0.png # Export the layer as PNGCopy the code

Manipulate PSD files

The psd_tools. API package provides a user-friendly API for handling PSD files.

Open an image:

from psd_tools import PSDImage
psd = PSDImage.open('my_image.psd')
Copy the code

Most of the data structures in PSD-Tools support printing in the IPython environment:

In [1]: PSDImage.open('example.psd')
Out[1]:
PSDImage(mode=RGB size=101x55 depth=8 channels=3)
  [0] PixelLayer('Background' size=101x55)
  [1] PixelLayer('Layer 1' size=85x46)
Copy the code

The inner layer can be accessed via iterators or indexes:

for layer in psd:
    print(layer)
    if layer.is_group():
        for child in layer:
            print(child)

child = psd[0][0]
Copy the code

Open PSD files can be saved:

psd.save('output.psd')
Copy the code

Operational use layer

In Photoshop, there are all kinds of layers.

The most basic layer type is PixelLayer:

print(layer.name)
layer.kind == 'pixel'
Copy the code

Some layer properties are editable, such as layer name:

layer.name = 'Updated layer 1'
Copy the code

There are inner layers in groups:

for layer in group:
    print(layer)

first_layer = group[0]
Copy the code

A TypeLayer is a layer with text:

print(layer.text)
Copy the code

ShapeLayer draws a vector shape, and the shape information is stored in the Vector_mask and Origination properties. Other layers can also have shape information as masks:

print(layer.vector_mask)
for shape in layer.origination:
    print(shape)
Copy the code

SmartObjectLayer embed or link an external file for non-destructive editing. The contents of the file can be accessed using the Smart_object property:

import io
if layer.smart_object.filetype in ('jpg', 'png'):
    image = Image.open(io.BytesIO(layer.smart_object.data))
Copy the code

SolidColorFill, PatternFill, and GradientFill are fill layers that paint the entire area if there is no associated mask. The AdjustmentLayer subclass represents the layer adjustments that are applied to make up images. See the Adjustment of the layers.

Export the data to PIL

Export the entire file as pil.image:

image = psd.composite()
image.save('exported.png')
Copy the code

Export a single layer, including mask and Clipping layers:

image = layer.composite()
Copy the code

Export the layer and mask separately without compositing:

image = layer.topil()
mask = layer.mask.topil()
Copy the code

To compose specific layers, such as layers other than text, use the layer_filter option:

image = psd.composite( layer_filter=lambda layer: layer.is_visible() and layer.kind ! = 'type')Copy the code

Please note that most layer effects and adjustment layers are not supported. The resultant results may look different from Photoshop.

Export the data to NumPy

PSDImage or layers can be exported as a numpy array using the numpy() method:

image = psd.numpy()
layer_image = layer.numpy()
Copy the code

More operations

1. Operate a PSD file

The PSDImage class is available in psd_image.py

1.Open a filefrom psd_tools import PSDImage
psd = PSDImage.open('my_image.psd')
Return an object of type PSDImage

Most of the data structures in #psd_tools support nice printing in an IPython environment.

# In [1]: PSDImage.open('example.psd')
# Out[1]:
# PSDImage(mode=RGB size=101x55 depth=8 channels=3)
# [0] PixelLayer('Background' size=101x55)
# [1] PixelLayer('Layer 1' size=85x46)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2.PSD properties (psd_image.py) some nonsense properties are also defined, in order to be like layer, such as: visible returns Ture directly. Here are some interesting attributes that are commonly used: psd.width# wide
psd.height # high
psd.size #(width, height) tuple
psd.offset #(left, top) tuple
psd.left # 0
psd.right #self.width
psd.top # 0
psd.bottom #self.height
psd.viewbox #(left, top, right, bottom) `tuple`

psd.bbox The smallest box (x,y,z,w) that surrounds all visible layers
psd.color_mode # Color modes, such as RGB, GRAYSCALE
psd.channels # Number of color channels
psd.depth # Pixel depth number
psd.version PSD = 1, PSB = 2
psd.has_preview #Returns if the document has real merged data. When True, `topil()`returns pre-composed data.
psd.has_thumbnail # Is there a thumbnail
psd.thumbnail # Return the thumbnail Image in pil. Image formatHere are some nonsensical properties that can be manipulated as layer: psd.is_visible()#True
psd.visible #True
psd.parent #None
psd.name   #'Root'
psd.kind #'psdimage'

print(str(psd.is_group()))PSD files directly passed in are also groupsThe layers of a PSD file can be traversed:for layer in psd:
print(layer)
if layer.is_group():
    for child in layer:
        print(child)

child = psd[0] [0]
The sequence of iterations is from background to foreground, as opposed to pre-1.7.x versions. Use reverse (List (PSD)) to iterate from foreground to background.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3.Save the PSD file: psd.save('output.psd')

4.PIL image.psd. topil(channel=None, **kwargs)
#channel:0 is R, 1 is G, 2 is B, -1 is A, according to the ChannelID class in Constants.py.

5.Merge PSD files. Psd.com Pose (force =False,bbox=None,**kwargs)

6.Generate a PSDImage object with PIL Imagefrom psd_tools import PSDImage
psd = PSDImage.frompilfrompil(image,compression=<Compression.PACK_BITS: 1>)
Copy the code

2. Manipulate a PSD layer

You can see the Layer class in layers.py

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1.Layer property (see Layer class in layers.py in the source code) layer.name# layer name (writable)
layer.kind # Layer category (string)

#(Group (layer group), Pixel (normal layer), Shape, Type (text layer), Smartobject,or PSdimage (PSD itself))
#shape Draws vector shapes. The shape information is stored in the Vector_mask and Origination properties. Other layers can also have shape information as masks:
# Smartobject embed or link external files for non-destructive editing. The contents of the file can be accessed using the Smart_Object property.

layer.layer_id #Layer ID.
layer.visible The layer itself is visible (writable).
layer.is_visible() Whether the layer is visible depends on the parent object. (Parent object is not visible, this layer is False even if visible is checked)

layer.opacity # transparency [0,255](writable)
layer.parent #Parent of this layer.
layer.is_group # is a group
layer.blend_mode # Mixed mode (writable), return BlendMode in Constants. Py
layer.has_mask # if there is a mask
layer.left # left coordinate (writable)
layer.top  # top coordinates (writable)
layer.right # right coordinates
layer.bottom # bottom coordinates
layer.width # layer width
layer.height # layer high
layer.offset #(left, top) tuple.
layer.size #(width, height) tuple.
layer.bbox #(left, top, right, bottom) tuple.
layer.has_pixels() # Whether there are pixels
layer.has_mask() # Is there a mask
layer.has_vector_mask() # Is there a vector mask
layer.mask Return: :py:class: '~psd_tools.api.mask. mask' or 'None'
layer.vector_mask # layer related to the vector mask return: : p y: class: ` ~ psd_tools. API. Shape. VectorMask ` or ` None `
layer.has_origination() # Whether there are real-time shape attributes
layer.origination # Real-time shape properties
layer.has_stroke() # Is there a sign
layer.stroke # strokes
layer.has_clip_layers() # Whether there is clipping
layer.clip_layers Clip layers associated with this layer.
layer.has_effects() # Whether there is effect processing
layer.effects # effect return: : p y: class: ` ~ psd_tools. API. Effects. The effects of `
layer.tagged_blocks #Layer tagged blocks that is a dict-like container of settings.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2.Get pil Image of the layer, Get pil Image of the layer.(Return the pil.Image object or if there are no pixelsNone`)
layer.topil(channel=None, **kwargs)

e.g.
from psd_tools.constants import ChannelID
image = layer.topil()
red = layer.topil(ChannelID.CHANNEL_0)
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3.Merge layers with their masks (Mask, vector mask,andClipping layers)(Return pil. Image object or return 'when there are no pixelsNone`)
layer.compose(bbox=NoneImage = layer.topil() mask = layer.mask.topil()from psd_tools import compose
clip_image = compose(layer.clip_layers)
Copy the code

The resources

  • [Python library] PSD file manipulation library — PSd_tools
  • The PSD – the tools documentation