SRC(1)
โจ NAME โจ
okay so bestie, this is the man page for src โ a.k.a. the psd-tools docs, section 1 of the manual ๐
psd-tools is a Python package for working with Adobe Photoshop PSD files, exactly as described in the spec over at https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ ๐
๐ INSTALLATION ๐
Use pip to install the package, no cap:
pip install psd-tools
For the advanced layer compositing features (the fancy stuff, bestie), install with the composite extra:
pip install psd-tools[composite]
This pulls in optional dependencies โ aggdraw, scipy, scikit-image โ which are required for ๐ซ:
- Vector shape and stroke rendering
- Gradient and pattern fills
- Layer effects rendering
Basic compositing operations work without these dependencies, by using cached previews or simple NumPy-based operations. lowkey huge ๐
Note: In order to extract images from 32bit PSD files, PIL/Pillow must be built with LITTLECMS or LITTLECMS2 support (apt-get install liblcms2-2orbrew install little-cms2) ๐
๐ฆ GETTING STARTED ๐ฆ
from psd_tools import PSDImage
psd = PSDImage.open('example.psd')
psd.composite().save('example.png')
for layer in psd:
print(layer)
image = layer.composite()
Check out the Usage documentation for more examples ๐
๐ FEATURES ๐
Supported ๐ฅ:
- Read and write of the low-level PSD/PSB file structure
- Raw layer image export in NumPy and PIL format
Limited support (it's giving "we're working on it" ๐ญ):
- Composition of basic pixel-based layers
- Composition of fill layer effects
- Vector masks
- Editing of some layer attributes such as layer name
- Basic editing of pixel layers and groups, such as adding or removing a layer
- Blending modes except for dissolve
- Drawing of bezier curves
Not supported ๐:
- Editing of various layers such as type layers, shape layers, smart objects, etc.
- Editing of texts in type layers
- Composition of adjustment layers
- Composition of many layer effects
- Font rendering
๐ Usage
๐ป Command line
The package provides command line tools to handle a PSD document:
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
Example โจ:
psd-tools show example.psd # Show the file content
psd-tools export example.psd example.png # Export as PNG
psd-tools export example.psd[0] example-0.png # Export layer as PNG
๐ธ Working with PSD document
The psd_tools.api package provides the user-friendly API to work with PSD files. PSDImage represents a PSD file ๐
Open an image:
from psd_tools import PSDImage
psdimage = PSDImage.open('my_image.psd')
Most of the data structure in the psd-tools supports pretty printing in an IPython environment. it's so cute when it does that ๐ฅน
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)
Internal layers are accessible by iterator or indexing:
for layer in psdimage:
print(layer)
if layer.is_group():
for child in layer:
print(child)
child = psdimage[0][0]
Note: The iteration order is from background to foreground, which is reversed from version prior to 1.7.x. Use reversed(psd) to iterate from foreground to background. yes bestie, this trips everyone up ๐
The opened PSD file can be saved:
psdimage.save('output.psd')
If the PSD File's layer structure was updated, saving it will update the ImageData section. However, the rendered image is likely different from the Photoshop's rendering, due to the limited rendering support in psd_tools. not us being honest about our flaws ๐
๐ง Working with Layers
There are various layer kinds in Photoshop, and each one is kind of a main character in its own way ๐
The most basic layer type is PixelLayer:
print(layer.name)
layer.kind == 'pixel'
Some of the layer attributes are editable, such as a layer name:
layer.name = 'Updated layer 1'
psd_tools experimentally supports the creation of a new PixelLayer from a PIL object โ the PIL image will be converted to the color mode of the PSD File given in parameter:
psdimage.create_pixel_layer(pil_image, name="Layer name")
To construct a layered PSD file from scratch (iconic behaviour, truly) โจ:
psdimage = PSDImage.new(mode='RGB', size=(640, 480), depth=8)
layer = psdimage.create_pixel_layer(pil_image, name="Layer 1", top=0, left=0, opacity=255)
group = psdimage.create_group(name="Group 1")
group.append(layer)
psdimage.save('new_image.psd')
See the function documentation for further parameter explanations ๐
Group has internal layers:
for layer in group:
print(layer)
first_layer = group[0]
Create a new group object.:
group = psdimage.create_group(name="Group name")
group.append(layer)
TypeLayer is a layer with texts:
print(layer.text)
Typographic details such as fonts, character styles, and paragraph styles are available via the typesetting property. See typesetting for full API reference:
for paragraph in layer.typesetting:
print(paragraph.style.justification)
for run in paragraph:
print(run.text, run.style.font_name, run.style.font_size)
ShapeLayer draws a vector shape, and the shape information is stored in vector_mask and origination property. Other layers can also have shape information as a mask:
print(layer.vector_mask)
for shape in layer.origination:
print(shape)
SmartObjectLayer embeds or links an external file for non-destructive editing. The file content is accessible via smart_object property:
import io
so = layer.smart_object
if so.detected_filetype in ('jpg', 'png'):
# Use open(external_dir=...) when processing untrusted PSD files.
with so.open() as f:
image = Image.open(io.BytesIO(f.read()))
SolidColorFill, PatternFill, and GradientFill are fill layers that paint the entire region if there is no associated mask. Sub-classes of AdjustmentLayer represents layer adjustment applied to the composed image. See Adjustment layers ๐
๐ง Modifying the layer structure
The layer structure of a PSD object can be modified through methods emulating a python list. bestie it's literally just a list, go off ๐
The internal model of the psd layer structure will be automatically updated. Moving a layer from a PSD to another will also automatically convert the PixelLayer to the target psd's color mode. auto-conversion?? slay โจ
The following are valid for both PSDImage and Group objects:
Set an item:
group[0] = layer
Add a layer or layers to a group:
group.append(layer)
group.extend(layers)
Insert a layer to a specific index in the group:
group.insert(3, layer)
Remove a layer from the a group:
group.remove(layer)
Pop a layer from the group:
layer = group.pop()
Emptying a layer group:
group.clear()
Get the index of a layer in the group:
index = group.index(layer)
Count the occurrences of a layer in a group:
count = group.count(layer)
Move a given list of layers in a newly created Group. If no parent group is given in parameter, the new group will replace the first layer of the list in the PSD structure:
group = psdimage.create_group(layer_list=[layer1, layer2, ...], name="New Group")
Some operations are available for all Layer objects.
Delete a layer from its layer structure:
group.remove(layer)
Layers can be moved from a group to another:
target_group.append(layer)
Layers can be moved within the group to change their order:
layer.move_up() # Will send the layer upward in the group
layer.move_down() # Will send the layer downward in the group
๐ผ๏ธ Exporting data to PIL
Export the entire document as PIL.Image:
image = psd.composite()
image.save('exported.png')
Export a single layer including masks and clipping layers:
image = layer.composite()
Export layer and mask separately without composition:
image = layer.topil()
mask = layer.mask.topil()
To composite specific layers, such as layers except for texts, use layer_filter option:
image = psd.composite(
layer_filter=lambda layer: layer.is_visible() and layer.kind != 'type')
Note: Advanced compositing features require optional dependencies. Install with:sh pip install psd-tools[composite]These dependencies (aggdraw,scipy,scikit-image) are needed for: - Vector shapes and strokes - Gradient and pattern fills - Layer effects Basic compositing works without them, by using cached previews or simple pixel-based operations. If a feature requires missing dependencies, anImportErrorwith installation instructions will be raised. Note that most layer effects are not supported. Adjustment layers have limited support (BrightnessContrast,Levels,Curves,Exposure,Invert,Posterize,Threshold). The compositing result may look different from Photoshop. ๐ญ
๐ข Exporting data to NumPy
PSDImage or layers can be exported to NumPy array by numpy() method:
image = psd.numpy()
layer_image = layer.numpy()
๐ 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. yeah we know, we know, deep breaths ๐
What changed:
- Dependencies
aggdraw,scipy, andscikit-imageare now optional - Basic compositing with NumPy continues to work without these dependencies
- Advanced features (vector masks, gradients, patterns, effects) require the
compositeextra
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
okay so which of the cute lil features are the divas that literally cannot function without composite deps? ๐ซถ
- Vector shape and stroke rendering โ๏ธ
- Gradient fills ๐
- Pattern fills ๐
- Layer effects rendering (drop shadows, strokes, etc.) ๐
Error handling: bestie, if you try to serve advanced-feature looks without the deps installed, the package does not ghost you โ you get a crystal-clear error:
ImportError: Advanced compositing features require optional dependencies.
Install with: pip install 'psd-tools[composite]'
Why this change: because we want psd-tools to run on platforms where some composite dependencies straight-up don't exist โ especially Python 3.14 on Windows, where aggdraw is not yet available. so this keeps the whole thing alive instead of crashing the party. ๐
Module Structure Changes ๐ธ
Version 1.12 did some internal glow-up refactoring that (mostly) doesn't touch the public APIs, promise:
- The
PSDclass moved frompsd_tools.psdtopsd_tools.psd.documentโ it's still importable frompsd_tools.psdtho, so don't panic ๐ซถ - Utils module got split into
registryandbin_utils(internal change, nothing to see here) - Composite module got reorganized for better type safety (again: internal change)
These changes maintain backward compatibility for public imports. slay. ๐
Type Annotations ๐
Version 1.12 adds comprehensive type annotations throughout the codebase. so if you run type checkers like mypy, you might suddenly discover type errors in your own code that were previously undetected. and that is genuinely a good thing โ the annotations help catch bugs earlier! catching them early is highkey iconic. โญ
v1.11 โจ
psd-tools 1.11 brings stronger type-safety via annotation, plus brand new public APIs for layer creation. so now this whole 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, so listen up bestie ๐ข
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 too.
Basic layer structure editing is supported in 1.10 โ you can add or remove a pixel layer, or change the grouping of layers. that's so cozy honestly. ๐ง
psd-tools 1.10 drops the compose module. Use composite instead. periodt.
version 1.10.x:
image = psd.composite()
layer_image = layer.composite()
v1.9 ๐ฆ
psd-tools 1.9 switches to NumPy based compositing. big era.
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. buckle up.
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(). (that's psd_tools.PSDImage.open for the record.)
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 are directly accessible by iterator or indexing. no more .layers middleman, we love direct communication. ๐
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. the math is mathing. ๐งฎ
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. peep the psd_tools.psd subpackage.
version 1.7.x:
psd.decoded_data
version 1.8.x:
psd._record
Drop pymaging support ๐ซถ
Pymaging support is dropped. it's gone, it's resting, we moved on.
Changelog ๐
1.17.4 (2026-06-24) ๐ฅ
- [security] Guard against oversized memory allocation from failed channel decompression (CWE-789, related to GHSA-8q6g-vjhf-jp8m)
- [api] Add
max_alloc_bytesparameter toPSDImage.open()for an opt-in per-document allocation budget cap
1.17.3 (2026-06-22) ๐ก๏ธ
- [security] Guard against uncontrolled memory allocation via crafted PSD canvas dimensions (GHSA-8q6g-vjhf-jp8m, #676)
- [fix] Fix
VirtualMemoryArraydimension computation for patterns (#672) - [fix] Fix smart object blank filetype field handling (#663)
- [chore] Bump
ruffto 0.15.18,pytestto 9.1.1,actions/checkoutto v7
1.17.2 (2026-06-04) โญ
- [fix] Disable Limited API for Windows Cython extension (#661)
- [chore] Bump
rufffrom 0.15.14 to 0.15.15 (#659)
1.17.1 (2026-05-27) ๐ก๏ธ
- [security] Fix path traversal in
SmartObject.save()andopen()(GHSA-2rmg-vrx8-9j2f, #657) - [chore] Bump
ruffto 0.15.14,mypyto 2.1.0
1.17.0 (2026-05-11) ๐จ
- [composite] Add Hue/Saturation adjustment layer composite algorithm (#646)
- [fix] Fix
float32safety in Hue/Saturation composite algorithm (#646) - [refactor] Use
IO[bytes]instead ofBinaryIOthroughout the codebase (#647) - [fix] Fix
mypy2.0 strict-bytes errors inrle.py - [ci] Migrate pre-commit hooks to uv-local runners; expand
ruffandmypyscope (#650) - [chore] Bump
mypyto 2.0.0,ruffto 0.15.12,pre-committo 4.6.0
1.16.0 (2026-04-24) ๐ง
- [composite] Add adjustment layer compositing support and fix pass-through compositing logic (#628)
- [fix] Fix fallback logic and density computation for user masks
- [refactor] Refactor composite subpackage for type safety and stability (#640)
- [docs] Update README and usage docs to reflect adjustment layer compositing support
- [chore] Bump
ruffto 0.15.11,mypyto 1.20.1
1.15.0.post1 (2026-04-14) ๐
- [ci] Fix release packaging:
version.pywas not bumped in the v1.15.0 release PR, causing wheels to be built with the wrong version
1.15.0 (2026-04-14) ๐
- [api] Add
layer_sizedoption toMask.topil()for correct rendering of inverted masks (#622, fixes #389) - [fix] Graceful fallback for zero-length channel data (#621, fixes #398)
- [fix] Make artboard background color color-mode aware (#620, fixes #395)
- [fix] Normalize color space in composite paint to fix mixed-colorspace stroke error (#618, fixes #397)
- [fix] Compute
VectorMask.bboxfrom full Bรฉzier curve extent, not just anchors (#613) - [refactor] Extract color conversion math into
psd_tools.color_convertmodule (#630) - [docs] Fix misleading
ImageResourcesignature docstring (#624, fixes #375) - [ci] Add Python 3.14 free-threaded (cp314t) wheel support (#633)
- [ci] Automate release tagging via
pull_requestclosed event (#611) - [ci] Add stale issue/PR workflow (#615)
- [chore] Bump
pytestto 9.0.3,ruffto 0.15.10,actions/checkoutto v6 (#625, #626, #627)
1.14.3 (2026-04-10) ๐ก๏ธ
- [security] Upgrade
Pygmentsto 2.20.0 to resolve ReDoS vulnerability (#609) - [fix] Don't add
USER_LAYER_MASKwhen PSD mode already carries transparency (#608) - [chore] Bump
Pillowfrom 12.1.1 to 12.2.0,mypyto 1.20.0,ruffto 0.15.9
1.14.2 (2026-03-19) โจ
- [fix] Detect transparency from negative
layer_countin preview path (#595)
1.14.1 (2026-03-17) ๐ธ
- [fix] Preserve alpha channel when compositing from layers (#593, fixes #592)
- [chore] Bump
rufffrom 0.15.4 to 0.15.6,pypa/cibuildwheelfrom 3.3.1 to 3.4.0
1.14.0 (2026-03-03) ๐
- [api] Add
PSDImage.background_colorproperty for reading and writing document background color (#586) - [api] Add high-level typesetting API for
TypeLayertext manipulation (#579) - [fix] Update contributing link from
mastertomainbranch (#580) - [chore] Bump
sphinx-rtd-themefrom 3.0.2 to 3.1.0,rufffrom 0.15.2 to 0.15.4 - [ci] Bump
actions/upload-artifactfrom 6 to 7,actions/download-artifactfrom 7 to 8
1.13.1 (2026-02-27) ๐
- [psd] Fix
TransferFunctioncurve values parsed as unsigned instead of signed shorts (#577) - [psd] Handle truncated
MaskParametersdata gracefully (#574, fixes #573) - [refactor] Drop Python <3.11 typing compatibility guards (#575)
- [docs] Improve mask module documentation and index layout (#576)
1.13.0 (2026-02-26) ๐
- [api] Add
Layer.sheet_colorproperty for reading and writing Photoshop layer color labels (#546) - [api] Add
Layer.create_mask(),remove_mask(), andupdate_mask()for pixel mask CRUD operations (#568) - [api] Auto-create layer masks from alpha channel in
PixelLayer.frompil()(#568) - [api] Add
Mask.disabledsetter for toggling layer mask visibility (#568)
1.12.2 (2026-02-24) ๐ฆ
- [api] Fix bbox to exclude clipping layers by default; add
include_clippingparameter toGroup.extract_bbox()(#566, fixes #547) - [api] Fix UTF-16 surrogate pair handling for emoji in text layers (#551)
- [security] Fix compression security issues (GHSA-24p2-j2jr-386w) (#549)
- [ci] Fix least-privilege permissions in CI workflows (#550)
- [ci] Add pre-commit hooks for linting, formatting, and type checking (#552)
- [ci] Add Dependabot configuration for automated dependency updates (#555)
- [dev] Extend
mypyandruffcoverage to thetestsdirectory (#554) - [docs] Clean up developer setup documentation (#553)
- [chore] Bump
Pillowfrom 11.3.0 to 12.1.1 (#563) - [chore] Bump
attrs,ipykernel,mypy,pytest, and various GitHub Actions
1.12.1 (2025-12-05) โ๏ธ
- [api] Fix preview image mode when saving PSD files (#542)
- [packaging] Upgrade
aggdrawto >=1.4.1 for Python 3.14 Windows support (#543)
1.12.0 (2025-11-17) ๐
- [packaging] Make composite dependencies optional via
psd-tools[composite]extra (#525) - [api] Lazy-load advanced composite features (vector masks, gradients, effects) so we're not out here importing optional dependencies unless you actually need them ๐
- [api] Basic
numpy-based compositing works withoutscipy,scikit-image, oraggdrawโจ - [api] Composite functionality raises
ImportErrorwith installation instructions only when advanced features are used - [api] Handle missing composite dependencies gracefully in
PSDImage.save()(#532) ๐ซถ - [packaging] Move
aggdraw,scipy, andscikit-imageto optional dependencies - [packaging] Keep
numpyas core dependency for raw pixel data access - [refactor] Move
PSDclass to dedicated document module (#530) - [refactor] Reorganize composite module structure and add type safety (#524)
- [refactor] Split
utilsmodule intoregistryandbin_utils(#537) - [refactor] Create shared API utils module (#538)
- [refactor] Improve type annotations and standardize imports (#539)
- [api] Add comprehensive type annotations to
psd_toolspackage (#536) - [tests] Add comprehensive type annotations to test suite (#534, #535)
- [tests] Add CI testing without composite dependencies (#533)
- [docs] Enhance package and module docstrings with comprehensive documentation (#531)
- [docs] Update installation instructions for optional composite support (#527)
- [docs] Convert README to Markdown (#527)
- [ci] Fix CI status badge in README (#523)
- [ci] Fix ReadTheDocs build by adding
Selfimport fallback - [ci] Fix Python 3.10
mypycompatibility (#526) - [chore] Remove unused deprecated decorator (#529)
- [chore] Remove redundant
MANIFEST.infile (#528)
โ ๏ธ Breaking change: Users who rely on advanced composite features (vector masks, gradient fills, pattern fills, stroke effects) must now install withpip install 'psd-tools[composite]'or install the optional dependencies separately. Basic pixel layer compositing continues to work with justnumpy. This change enables support for Python 3.14 on Windows and other platforms where composite dependencies may not be available. ๐ yeah bestie it's real
๐ธ 1.11.1 (2025-11-17)
- [ci] Disable Python 3.14 on Windows due to
aggdrawunavailability (#521) ๐ญ
๐ 1.11.0 (2025-11-09)
- [api] Add public APIs for layer and group creation (#517) ๐ฅ
- [api] Type safety improvements (#516)
- [api] Refactor
psd_tools.apiimport dependencies (#515) - [api] Fix group blend mode returning
None(#514) - [dev] Add Claude Code support (#511)
- [api] Add type annotation to more APIs (#509, #510, #512)
- [api] Add
fill_opacityandreference_pointattributes (#507, #508) - [psd] Improve pretty print of
Subpath(#506)
๐ 1.10.13 (2025-10-02)
- [docs] Fix incorrect method name in the usage (#504)
- [api] Fix updated status flag (#503)
- [api] Add tree traversal API (#502)
- [psd] Fix crash when reading malformed
Levelsrecord (#501)
๐ฆ 1.10.12 (2025-09-25)
- [api] Drop
docoptdependency (#498) - [api] Remove unused imports (#497)
- [api] Fix stacked clip layer handling (#496)
โจ 1.10.11 (2025-09-24)
- [tests] Drop python2 compatibility code (#494)
- [api] Fix clip layer handling (#493)
- [psd] Workaround CAI tagged block reconstruction (#492)
๐ 1.10.10 (2025-09-18)
- [api] Fix clipping with stroke composite (#489)
- [ci] Fix documentation build (#486, #487)
- [ci] Introduce ABI3 wheels (#483, #485)
- [api] Fix
PyCMSErrorin composite (#484) - [api] Fix
ImageMathdeprecation warning (#482)
๐ 1.10.9 (2025-08-07)
- [psd] Allow linked layer version 8 (#476)
๐ง 1.10.8 (2025-06-06)
- [ci] Update CI configuration (#471)
- [psd] Workaround levels adjustment layer parsing (#470)
- [psd] Support CAI, GenI, OCIO tagged blocks (#469)
๐ 1.10.7 (2025-02-25)
- [psd] Fix missing gradient method (#465)
๐ 1.10.6 (2025-02-18)
- [security] Update
pillowdependency (#462) ๐
๐ธ 1.10.5 (2025-02-18)
- [security] Update
pillowdependency (#461) ๐
๐ 1.10.4 (2024-11-25)
- [api] Allow
Pathobjects forPSDImageopen (#452)
๐ซ 1.10.3 (2024-11-20)
- [psd] Fix data corruption by irregular OSType (#449)
- [api] Add type annotation to the high-level APIs (#448)
๐ฆ 1.10.2 (2024-10-23)
- [api] Add channel info via
DisplayInfo(#443) - [api] Support layer locking (#442)
โจ 1.10.1 (2024-10-10)
- [api] Fix artboard creation (#438)
- [api] Fix layer conversion issue (#435)
๐ฅ 1.10.0 (2024-09-26)
- [api] Support basic layer structure editing (#428)
- [api] Drop deprecated compose module (#432)
๐ 1.9.34 (2024-07-01)
- [api] Support text type property (#419)
- [psd] Improve RLE decoding error handling (#417)
๐ 1.9.33 (2024-06-14)
- [psd] Raise IO error instead of assertion (#413)
- [api] Add a new property to
SmartObject:transform_box(#412) - [ci] Migrate code formatter to ruff (#408)
๐ 1.9.32 (2024-05-01)
- [psd] Fix incorrect group divider handling (#399)
๐ 1.9.31 (2024-02-26)
- [psd] Reworked packbits/rle algorithms (#392)
๐ง 1.9.30 (2024-01-06)
- [ci] Fix missing pyx file in sdist (#386)
๐ 1.9.29 (2024-01-04)
- [ci] Update CI configuration (#383)
- [dev] Migrate the builder to
pyproject.toml - [dev] Update linter and formatter to
pysen - [dev] Deprecate
tox - [psd] Add new color sheet (#380)
- [psd] Fix transparency check (#370)
๐ธ 1.9.28 (2023-07-04)
- [psd] Add alternate 8ELE signiture for 8BIM tagged block (#367)
๐ 1.9.27 (2023-06-27)
- [composite] Fix regression by #361 (#364)
๐ซ 1.9.26 (2023-06-21)
- [composite] Read HSB colors in RGB and CMYK color modes (#361)
- [ci] Update CI configuration (#362)
๐ฆ 1.9.25 (2023-06-19)
- [composite] Fix hue, sat, and vivid light (#359)
โจ 1.9.24 (2023-01-17)
- [psd] Support float RGB values (#350)
- [psd] Workaround stroke class ID (#346)
- [ci] Update CI configuration (#347)
- [composite] Fix group clipping (#336)
๐ฅ 1.9.23 (2022-09-26)
- [api] Add bbox invalidation when toggling layer visibility (#334)
๐ 1.9.22 (2022-09-09)
- [psd] Add support for v3 gradient map adjustment layer (#330)
๐ 1.9.21 (2022-06-18)
- [api] Fix incorrect
has_effectsbehavior (#322) - [composite] Improve blending numerical stability (#321)
- [composite] Improve non-RGB modes and transparency (#319, @Etienne-Gautier)
- [psd] Workaround assertion error in broken file (#320)
๐ 1.9.20 (2022-05-16)
- [ci] Update CI configuration (#313 #314)
- [composite] Fix composite errors (#312)
- [psd] Suppress
vowvtagged blocks (#306)
๐ 1.9.19 (2022-04-15)
- [composite] Fix rasterized shape composite (#301 #302)
๐ง 1.9.18 (2021-08-20)
- [api] Fix missing effect attributes (#284)
- [package] Support additional platforms (i686, aarch64, universal2, win32)
- [package] Drop py36 support
๐ 1.9.17 (2021-01-15)
- [api] Fix incorrect fill layer parse (fix #254)
๐ธ 1.9.16 (2020-09-24)
- [package] Drop py27 and py35 support
- [psd] Workaround Enum bug (fix #241)
- [composite] Fix transparency issue (fix #242)
- [composite] Fix mask disable flag (fix #243)
- [api] Add workaround for creating PSB (fix #246)
- [api] Fix incorrect adjustment parse (fix #247)
๐ 1.9.15 (2020-07-17)
- [composite] Fix ignored clip layers for groups.
- [composite] Fix out-of-viewport stroke effect.
๐ซ 1.9.14 (2020-07-10)
- [api] Bugfix for
PSDImagecompositelayer_filteroption. - [api] Bugfix for transparency and alpha distinction.
- [psd] Rename
COMPOSITOR_INFO. - [composite] Fix stroke effect target shape.
๐ฆ 1.9.13 (2020-05-25)
- [api] Bugfix for
PSDImageinit internal.
โจ 1.9.12 (2020-05-20)
- [psd] Bugfix for
CurvesExtraMarkerread.
๐ฅ 1.9.11 (2020-05-01)
- [composite] Fix layer check.
๐ 1.9.10 (2020-04-21)
- [psd] Fix engine data parser.
๐ 1.9.9 (2020-03-30)
- [composite] Fix stroke effect argument.
๐ 1.9.8 (2020-03-18)
- [composite] Fix incorrect fill opacity handling in compositing.
- [composite] Fix incorrect alpha for patterns.
๐ 1.9.7 (2020-03-17)
- [composite] Fix path operation for merged components.
- [composite] Fix vector mask compositing condition.
๐ง 1.9.6 (2020-03-16)
- [composite] Fix incorrect alpha channel handling in composite.
๐ 1.9.5 (2020-03-11)
- [api] Add
ignore_previewoption toPSDImage.composite. - [composite] Improve stroke effect composition for vector masks.
- [composite] Avoid crash when there is an erroneous subpath.
- [composite] Workaround possible divide-by-zero warn in stroke composition.
- [composite] Fix incorrect pattern transparency handling.
- [composite] Fix ignored effects in direct group composition.
- [composite] Fix incorrect opacity handling for clip layers.
๐ธ 1.9.4 (2020-03-11)
- [compression] Security fix, affected versions are 1.8.37 - 1.9.3. ๐จ
๐ 1.9.3 (2020-03-10)
- [composite] Fix memory corruption crash for pattern data in PSB files.
- [psd] Add image data pretty printing.
๐ซ 1.9.2 (2020-03-03)
- [psd] Add missing resource ID.
- [psd] Fix pretty printing regression.
- [psd] Fix big tag key for linked layers.
- [psd] Support
frgbtag. - [psd] Support
sgrpmetadata key. - [psd] Support
patttag. - [psd] Workaround unknown engine data.
๐ฆ 1.9.1 (2020-02-28)
- [psd] Minor bugfix.
โจ 1.9.0 (2020-02-26)
- [composite] Implement NumPy-based compositing functionality.
- [composite] Support blending modes other than dissolve.
- [composite] Support blending in RGB, CMYK, Grayscale.
- [api] Introduce NumPy array export method.
- [api] Drop deprecated methods from v1.7.x such as
as_PIL. - [api] Deprecate
composemethod. - [compression] Rename
packbitstorle. - [compression] Improve RLE decode efficiency.
- [tests] Additional compositing tests.
๐ฅ 1.8.38 (2020-02-12)
- [composer] fix crash when gradient fill is in stroke.
๐ 1.8.37 (2020-02-07)
- [compression] Remove
packbitsdependency and introduce cython implementation. - [deploy] Move CI provider from Travis-CI to Github Actions.
- [deploy] Start distributing binary wheels.
๐ 1.8.36 (2019-12-26)
- [psd] add safeguard for malformed global layer mask info parser.
๐ 1.8.35 (2019-12-26)
- [api] remove duplicate
has_mask()definition. - [composer] fix empty effects check.
๐ 1.8.34 (2019-11-28)
- [api] fix
compose()arguments. - [psd] fix attrs version dependency.
๐ง 1.8.33 (2019-11-28)
- [api] add
include_invisibleoption toGroup.extract_bbox. - [psd] fix deprecated attrs api.
๐ 1.8.32 (2019-11-28)
- [psd] fix 16/32 bit file parsing bug introduced in 1.8.17.
๐ธ 1.8.31 (2019-11-27)
- [psd] bugfix reading psb.
- [psd] bugfix reading slices resource.
[security]so bestie, the dependency got bumped topillow >= 6.2.0. stay safe out here ๐
1.8.30 (2019-09-24)
[psd]we now do a little workaround so reading a less-than-4-byte int out of a malformed psd file doesn't ruin your whole day โจ
1.8.29 (2019-09-10)
[composer]fixed the vector mask bbox situation when composing ๐
1.8.28 (2019-09-09)
[api]Effects.__repr__()was being weird when the data was empty โ fixed, slay ๐
1.8.27 (2019-08-29)
[api]PSDImage.openandPSDImage.savenow accept theencodingparam, iconic[deploy]bugfix for the travis deployment condition ๐ซถ
1.8.26 (2019-08-28)
[composer]group mask is supported now ๐ซ
1.8.25 (2019-08-07)
[api]the return type ofPSDImage.color_modegot changed to enum ๐[api]reading of bitmap color mode is supported now[api]thechanneloption is supported in thetopil()method ๐ธ
1.8.24 (2019-07-25)
[composer]experimental support for commutative blending modes, very much a science moment ๐งช
1.8.23 (2019-06-24)
[composer]fixed clipping on alpha-less images[composer]fixed the stroke effect for flat planes[composer]workaround for insufficient knots[composer]fix for custom color space ๐
1.8.22 (2019-06-19)
- fixed the pass-through composing bug
- fixed alpha blending in effects
- fixed vector mask composition
- experimental support for shape stroke โจ
- experimental support for stroke effect โจ
1.8.21 (2019-06-18)
- the effect property return type changed from
strto enum - gradient quality got improved, lowkey a glow-up
- fill opacity and layer opacity are supported now
- added the
tmlnkey in metadata setting ๐
1.8.20 (2019-06-13)
- gradient styles are supported now ๐
1.8.19 (2019-06-11)
- fixed the broken
psd_tools.composer.vectormodule from 1.8.17 ๐ญ - experimental support for color noise gradient
- bugfix for clip masks
- bugfix for CMYK composing
1.8.17 (2019-06-05)
- moved the
psd_tools.api.composermodule over to thepsd_tools.composerpackage - 19 blending modes are supported in the composer, no cap
- fill opacity is supported
- fixed image size when composing with masks
- renamed
TaggedBlockIDtoTag - renamed
ImageResourceIDtoResource - added a
bytesmixin to Enum constants - replaced Enum keys with raw values in
psd_tools.psd.base.Dictclasses ๐
1.8.16 (2019-05-24)
- fixed broken group compose from 1.8.15
- fixed missing pattern / gradient composition in vector stroke content ๐ธ
1.8.15 (2019-05-23)
- coding style fix, we love a tidy moment
- fixed the
compose()bboxoption ๐ซถ
1.8.14 (2019-04-12)
- added a dependency on
aggdraw - bezier curves in vector masks are supported now
- path operations are supported now
- fixed
compose(force=True)behavior - fixed the default background color in the composer
- improved pattern overlay parameter support
- fixed gradient map generation for a single stop โญ
1.8.13 (2019-04-05)
- fixed the
engine_dataunknown tag format - fixed
composefor extra alpha channels - workaround for a
pillow6.0.0bug ๐
1.8.12 (2019-03-25)
- added the
apply_iccoption in pil io โจ
1.8.11 (2019-03-14)
- introduced the terminology module
- reduced memory use in read
- added main testing ๐
1.8.10 (2019-02-27)
- fixed the PSB extn key size bug
1.8.9 (2019-02-21)
- documentation updates
- introduced the
Artboardclass ๐
1.8.8 (2019-02-20)
- reverted the package name back to
psd_tools - prepared for merging into the main repo
1.8.7 (2019-02-15)
- minor bugfix, tiny lil thing ๐ฆ
1.8.6 (2019-02-14)
- changed the
_psdpointer inPSDImage - added the
versionproperty - fill effects are supported in the composer now ๐
1.8.5 (2019-02-05)
- changed the tagged block / image resource singleton accessor in the user API
- added documentation on iterator order
- fixed the export setting 1 big key config
- fixed the computer info big key config ๐ธ
1.8.3 (2019-02-01)
- added channel size checking in
topil - added
mlstmetadata decoding - fixed the key collision issue in descriptor
- performance improvement for packbit encoding/decoding
- dropped the cython dependency in the travis config
- implemented
thumbnail,is_group, andparentmethods inPSDImage๐
1.8.0 (2019-01-24)
- major API changes, buckle up bestie
- package name changed to
psd_tools2 - completely rewritten decoding subpackage
psd_tools2.psd - improved composer functionality
- file write support ๐ฅ
- dropped the cython compression module, which makes the package pure-python
- dropped
pymagingsupport
1.7.30 (2019-01-15)
- composer alpha blending fix
- documentation fix
1.7.28 (2019-01-09)
cinftagged block is supported now ๐ซ
1.7.27 (2018-12-06)
- added the missing extra image resource block signatures
1.7.26 (2018-12-03)
- moved the
psd_toolstests undertests/psd_tools๐
1.7.25 (2018-11-27)
- fixed alpha channel visibility of the composed image
1.7.24 (2018-11-21)
- fixed the unit rectangle drawing size
1.7.23 (2018-11-20)
- fixed ignored visibility in bbox calculation ๐ธ
1.7.22 (2018-10-12)
- dropped py34 support
- fixed the
tobytesdeprecation warning
1.7.21 (2018-10-10)
- fixed the gradient descriptor bug ๐ฆ
1.7.20 (2018-10-09)
- fixed the coloroverlay bug
- fixed the gradient angle bug
- fixed the curves decoder bug
1.7.19 (2018-10-02)
- fixed the descriptor decoder โจ
1.7.18 (2018-09-26)
- added shape rendering in
compose() - added grayscale support ๐
1.7.17 (2018-09-21)
- fixed the
has_pixel()condition
1.7.16 (2018-08-29)
- fixed fill opacity in
compose() - workaround for broken
PrintFlags๐ซถ
1.7.15 (2018-08-28)
- fixed the color overlay issue in
compose()๐
1.7.14 (2018-08-24)
- fixed the
verbosearg for python 3.7 compatibility
1.7.13 (2018-08-10)
- fixed
has_pixel()for partial channels - color overlay is supported in
compose()now ๐
1.7.12 (2018-06-25)
- fixed mask rendering in
compose(Thanks @andrey-hider and @nkato) ๐
1.7.11 (2018-06-11)
- unicode bugfixes ๐
1.7.10 (2018-06-06)
- fixed descriptor decoding errors
- minor bugfixes
1.7.9 (2018-06-05)
- fixed
UnicodeErrorin exif - workaround for irregular descriptor names
- added undocumented
extntagged block decoding - moved the duplicated icc module to a subpackage
- PIL rendering with extra alpha channels is supported now โจ
1.7.8 (2018-05-29)
- updated the documentation
- fixed PEP8 compliance
- renamed
merge_layerstocompose๐ฆ
1.7.7 (2018-05-02)
- fixed the white background issue in
as_PIL()
1.7.6 (2018-04-27)
- added quality testing
- fixed the disabled mask ๐
1.7.5 (2018-04-25)
- fixed the
has_mask()condition - added mask composition in
merge_layers() - fixed mask display ๐ธ
1.7.4 (2018-03-06)
- fixed the infinity loop in
print_tree()๐ญ
1.7.3 (2018-02-27)
- added the vector origination API
- fixed shape and vector mask identification
- changed the enum name conversion
- updated the docs โญ
1.7.2 (2018-02-14)
- added the adjustments API
- added the mask API
- bugfix for
tagged_blocksdecoders ๐
1.7.1 (2018-02-08)
- added the mask user API
- added the layer coordinate user API
- added the vector mask and vector stroke API
- cleaned up the user API
- added automatic descriptor conversion ๐ซถ
1.7.0 (2018-01-25)
- cleaned up the user API organization
- removed the json encoder api
- made cli a package main ๐
1.6.7 (2018-01-17)
- workaround for anaconda 2.7 pillow
- bbox existence checkf ๐
1.6.6 (2018-01-10)
- experimental clipping support in
merge_layer() - reverted
as_PIL()inAdjustmentLayer๐ซ
1.6.5 (2017-12-22)
- Small fix for erroneous unicode path name ๐
1.6.4 (2017-12-20)
- Add
all_layers()method - Add
_image_resource_blocksproperty - Add
thumbnail()method โจ
1.6.3 (2017-09-27)
- documentation updates
- github repository renamed to
psd-tools2 AdjustmentLayerfix ๐ธ
1.6.2 (2017-09-13)
- layer class structure reorganization
- added the
EffectsAPI - added
TypeLayerAPI methods ๐
1.6 (2017-09-08)
PSDImageuser API update- user API adds distinct layer types
- Sphinx documentation ๐ฆ
1.5 (2017-07-13)
- implemented many decodings of image resources and tagged blocks
- implemented
EngineDatatext information - user API for getting mask and patterns
- user API to calculate bbox for shape layers ๐
1.4 (2017-01-02)
- Fixed reading of layer mask data (thanks Evgeny Kopylov)
- Python 2.6 support is dropped
- Python 3.6 support is added (thanks Leendert Brouwer)
- extension is rebuilt with Cython 0.25.2 โญ
1.3 (2016-01-25)
- fixed references decoding (thanks Josh Drake)
- fixed PIL support for CMYK files (thanks Michael Wu)
- optional C extension is rebuilt with Cython 0.23.4
- Python 3.2 support is dropped; the package still works in Python 3.2, but the compatibility is no longer checked by tests, and so it can break in future
- declare Python 3.5 as supported ๐
1.2 (2015-01-27)
- implemented extraction of embedded files (embedded smart objects) - thanks Volker Braun
- optional C extension is rebuilt with Cython 0.21.2
- hg mirror on bitbucket is dropped, sorry! ๐ญ
1.1 (2014-11-17)
- improved
METADATA_SETTINGdecoding (thanks Evgeny Kopylov) - layer comps decoding (thanks Evgeny Kopylov)
- improved smart objects decoding (thanks Joey Gentry)
- user API for getting layer transforms and placed layer size (thanks Joey Gentry)
- IPython import is deferred to speedup
psd-tools.pycommand-line utility _RootGroup.__repr__is fixed- warning message building is more robust
- optional C extension is rebuilt with Cython 0.21.1 โจ
1.0 (2014-07-24)
- Fixed reading of images with layer masks (thanks Evgeny Kopylov)
- improved mask data decoding (thanks Evgeny Kopylov)
- fixed synchronization in case of
8B64signatures (thanks Evgeny Kopylov) - fixed reading of layers with zero length (thanks Evgeny Kopylov)
- fixed Descriptor parsing (thanks Evgeny Kopylov)
- some of the descriptor structures and tagged block constants are renamed (thanks Evgeny Kopylov)
PATH_SELECTION_STATEdecoding (thanks Evgeny Kopylov)- the library is switched to setuptools; docopt is now installed automatically ๐
0.10 (2014-06-15)
- Layer effects parsing (thanks Evgeny Kopylov)
- trailing null bytes are stripped from descriptor strings (thanks Evgeny Kopylov)
"Reference"and"List"descriptor parsing is fixed (thanks Evgeny Kopylov)- scalar descriptor values (doubles, floats, booleans) are now returned as scalars, not as lists of size 1 (thanks Evgeny Kopylov)
- fixed reading of
EngineDatapast declared length (thanks Carlton P. Taylor) "background color"Image Resource parsing (thanks Evgeny Kopylov)psd_tools.decoder.actions.Enum.enumfield is renamed topsd_tools.decoder.actions.Enum.value(thanks Evgeny Kopylov)- code simplification โ constants are now bytestrings, exactly as they should have been all along (ty Evgeny Kopylov ๐);
- Python 3.4 is supported ๐.
๐ซ 0.9.1 (2014-03-26)
- merging of transparent layers got way better (thank you Vladimir Timofeev โจ);
- fixed layer merging and bounding box calculations for empty layers (thanks again Vladimir Timofeev ๐ซถ);
- the C extension is rebuilt with Cython 0.20.1.
๐ 0.9 (2013-12-03)
- the
psd-tools.pycommand-line interface changed, and a'debug'command was added ๐; - pretty-printing of internal structures, it's giving aesthetic;
pymagingsupport is fixed;'MeSa'is now allowed as a signature for image resource blocks (thanks Alexey Buzanov ๐ );- the
psd_tools.debug.debug_viewutility function is fixed; - Photoshop CC constants are added ๐;
- Photoshop CC vector origination data is decoded;
- binary data is preserved if descriptor parsing fails (no data loss, we don't do that here);
- more verbose logging for the PSD reader;
- the channel data reader became more robust โ it now does not read past the declared channel length;
- the
psd-tools.py --versioncommand is fixed; lsdktagged blocks parsing: this fixes some issues with layer grouping (thanks Ivan Maradzhyiski for the bug report and the patch ๐);- CMYK images support is added (thanks Alexey Buzanov, Guillermo Rauch and
https://github.com/a-e-mfor the help ๐); - Grayscale images support is added (thanks
https://github.com/a-e-m); - LittleCMS is now optional (but it is still required to get proper colors) โ so like, optional unless you want correct colors, bestie ๐ญ.
๐ฆ 0.8.4 (2013-06-12)
PointandMillimetertypes are added toUnitFloatType(thanks Doug Ellwanger โจ).
๐ธ 0.8.3 (2013-06-01)
- some issues with descriptor parsing are fixed (thanks Luke Petre).
๐ 0.8.2 (2013-04-12)
- Python 2.x: reading data from file-like objects is fixed (thanks Pavel Zinovkin).
๐ 0.8.1 (2013-03-02)
- fixed parsing of layer groups without an explicit
OPEN_FOLDERmark; - the Cython extension is rebuilt with Cython 0.18.
โญ 0.8 (2013-02-26)
- descriptor parsing (thanks Oliver Zheng ๐);
- text (as string) is extracted from text layers (thanks Oliver Zheng);
- improved support for optional building of the Cython extension.
๐ง 0.7.1 (2012-12-27)
- a typo is fixed:
LayerRecord.cilppingshould beLayerRecord.clipping. Thanks Oliver Zheng ๐.
๐ 0.7 (2012-11-08)
- highly experimental: basic layer merging is implemented (like, it's now possible to export a layer group to a PIL image);
Layer.visibleno longer takes group visibility into account;Layer.visible_globalis the oldLayer.visible;psd_tools.user_api.combined_bboxmade public;Layer.widthandLayer.heightare removed (uselayer.bbox.widthandlayer.bbox.heightinstead);pil_support.composite_image_to_PILis renamed topil_support.extract_composite_imageandpil_support.layer_to_PILis renamed topil_support.extract_layer_imageso thatpil_supportandpymaging_supporthave the same API.
๐ 0.6 (2012-11-06)
psd.composite_image()is renamed topsd.as_PIL();- Pymaging support: the
psd.as_pymaging()andlayer.as_pymaging()methods.
๐ 0.5 (2012-11-05)
- support for zip and zip-with-prediction compression methods is added;
- support for 16/32bit layers is added;
- an optional Cython extension for faster zip-with-prediction decompression;
- other speed improvements ๐๏ธ.
๐ซถ 0.2 (2012-11-04)
- initial support for 16bit and 32bit PSD files: psd-tools v0.2 can read composite (merged) images for such files and extract information (names, dimensions, hierarchy, etc.) about layers and groups of 16/32bit PSD; extracting image data for distinct layers in 16/32bit PSD files is not supported yet;
- better
Layer.__repr__; - a
bboxproperty forGroup.
๐ 0.1.4 (2012-11-01)
Packaging is fixed in this release.
๐ 0.1.3 (2012-11-01)
- better support for 32bit images (still incomplete);
- the reader is able to handle "global" tagged layer info blocks that were previously discarded.
โจ 0.1.2 (2012-10-30)
- warn about 32bit images;
- transparency support for composite images.
๐ 0.1.1 (2012-10-29)
Initial release (v0.1 had packaging issues).
๐ Contributing
Development happens at github: bug tracker https://github.com/psd-tools/psd-tools/issues. Feel free to submit bug reports https://github.com/psd-tools/psd-tools/issues/new or pull requests ๐ซถ. Attaching an erroneous PSD file makes the debugging process faster. Such a 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 <#module-psd_tools.psd>: the subpackage that reads/writes the low-level binary structure of the PSD/PSB file. The core data structures are built aroundattrs <https://www.attrs.org/en/stable/index.html#>classes that all implementreadandwritemethods. Each data object tries to resemble the structure described in the specificationhttps://www.adobe.com/devnet-apps/photoshop/fileformatashtml/. Although documented, the specificationhttps://www.adobe.com/devnet-apps/photoshop/fileformatashtml/is far from complete and some parts are even inaccurate. When psd-tools finds an unknown data structure, the package keeps such data as bytes in the parsed result ๐.psd_tools.api <#module-psd_tools.api>: the user-facing API that implements various easy-to-use methods which manipulate the low-levelpsd_tools.psd <#module-psd_tools.psd>data structures. This is the primary interface for most users ๐.psd_tools.composite <#module-psd_tools.composite>: the rendering engine for layer compositing and blending. 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 thecompositeextra.psd_tools.compression <#module-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 https://developer.adobe.com/photoshop/uxp/2022/ps_reference/ 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 the 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
https://peps.python.org/pep-0440/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 the release workflow, 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
https://github.com/psd-tools/psd-tools/actionsfor workflow status - verify the release on GitHub
https://github.com/psd-tools/psd-tools/releases - confirm the package is available on PyPI
https://pypi.org/project/psd-tools/
- check the Actions tab
๐ Acknowledgments
Great thanks to all the contributors https://github.com/psd-tools/psd-tools/graphs/contributors ๐ซถ.
๐ฆ psd_tools
See Usage <> for examples.
๐ PSDImage
class psd_tools.PSDImage(data: PSD <#psd_tools.psd.PSD>)
Photoshop PSD/PSB document ๐ธ.
The low-level data structure is accessible at PSDImage._record.
Example:
from psd_tools import PSDImage
psdimage = PSDImage.open('example.psd')
image = psdimage.composite()
for layer in psdimage:
layer_image = layer.composite()
append(layer: Layer <#psd_tools.api.layers.Layer>) -> None
Add a layer to the end (top) of the group.
This operation rewrites the internal references of the layer. Adding the same layer will not create a duplicate ๐.
Parameters
- layer โ the layer to add.
Raises
TypeErrorโ if the provided object is not aLayerinstance.ValueErrorโ if attempting to add a group to itself.
property background_color: float | tuple[float, ...] | None
Background color for the merged composite image. Writable โ๏ธ.
When you set it, save() composites layers against an opaque backdrop of this color instead of a transparent one. It's giving major RGB-mode PSD files where the transparent areas should show up as a specific color (like white ๐ฅ) in the merged composite. obsessed with the utility tbh
Values live in the [0.0, 1.0] range, matching the composite() color parameter โ so:
- RGB / Grayscale:
1.0= white,0.0= black - CMYK:
(0.0, 0.0, 0.0, 0.0)= white (no ink) ๐จ๏ธ
Use a scalar for uniform color, or a tuple for per-channel values. Set it to None for a transparent backdrop (the legacy behavior, bestie ๐
).
Documents created via new() have this set automatically from the color parameter. so convenient fr fr โจ
Returns: float, tuple[float, ...], or None
Example:
psd = PSDImage.new('RGB', (640, 480), color=1.0)
psd.save('output.psd') # White background, 3 channels (no alpha)
property bbox: tuple[int, int, int, int]
The minimal bounding box that contains all the visible layers ๐ the tightest little hug around everything you can actually see.
Wanna grab the viewport bounding box instead? Use viewbox (psd_tools.api.psd_image.PSDImage.viewbox). And when the psd is empty, bbox is equal to the canvas bounding box โ yes, like an empty canvas still has a box ๐ซถ
Returns: (left, top, right, bottom) tuple.
property bottom: int
Bottom coordinate ๐ just the bottom, that's the whole vibe.
Returns: int
property channels: int
How many color channels the doc has ๐.
Returns: int
clear() -> None
Clears the group. poof ๐จ gone.
Heads up bestie, this operation rewrites the internal references of the layers โ so it's not just a cosmetic delete, it's a lil internal remix.
Returns: None
property color_mode: ColorMode
Document color mode, such as 'RGB' or 'GRAYSCALE' ๐จ see ColorMode (psd_tools.constants.ColorMode).
Returns: ColorMode (psd_tools.constants.ColorMode)
property compatibility_mode: CompatibilityMode
Sets the compositing and layer organization compatibility mode. Writable ๐
This property checks whether the PSD file is compatible with specific authoring tools, such as Photoshop or CLIP Studio Paint. Different authoring tools may have different ways of handling layers, such as the use of clipping masks for groups. Default is Photoshop compatibility mode.
Returns: CompatibilityMode (psd_tools.constants.CompatibilityMode)
composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray | None = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, ignore_preview: bool = False, apply_icc: bool = True) -> Image
Composite the PSD image ๐ผ๏ธ the main character move where all your layers become one pretty picture.
Parameters
viewportโ Viewport bounding box specified by an(x1, y1, x2, y2)tuple. Default is the viewbox of the PSD.ignore_previewโ Boolean flag for whether to skip compositing when a pre-composited preview is available.forceโ Boolean flag to force vector drawing.colorโ Backdrop color specified by a scalar or tuple of scalars. The color value should be in[0.0, 1.0]. For example,(1., 0., 0.)specifies red in RGB color mode.alphaโ Backdrop alpha in[0.0, 1.0].layer_filterโ Callable that takes a layer as argument and returns whether the layer is composited. Default isis_visible().
Returns: PIL.Image.
count(layer: Layer) -> int
Counts the number of occurrences of a layer in the group ๐ข like a "how many of u are there" check.
Parameters
layerโ The layer to count.
create_group(layer_list: Iterable[Layer] | None = None, name: str = 'Group', opacity: int = 255, blend_mode: BlendMode = BlendMode.PASS_THROUGH, open_folder: bool = True) -> Group
Create a new group layer and add it to the PSDImage ๐ fresh folder energy.
Example:
group = psdimage.create_group(name='New Group')
group.append(psdimage.create_pixel_layer(image, name='Layer in Group'))
Parameters
layer_listโ Optional list of layers to add to the group.nameโ Name of the new group.opacityโ Opacity of the new layer (0-255).blend_modeโ Blend mode of the new layer, default isBlendMode.PASS_THROUGH.open_folderโ Whether the group is an open folder in the Photoshop UI.
Returns: The created Group (psd_tools.api.layers.Group) object.
create_pixel_layer(image: Image, name: str = 'Layer', top: int = 0, left: int = 0, compression: Compression = Compression.RLE, opacity: int = 255, blend_mode: BlendMode = BlendMode.NORMAL) -> PixelLayer
Create a brand new pixel layer and add it to the PSDImage โจ.
Example:
psdimage = PSDImage.new("RGB", (640, 480))
layer = psdimage.create_pixel_layer(image, name='Layer 1')
Parameters
nameโ Name of the new layer.imageโ PIL Image object.topโ Top coordinate of the new layer.leftโ Left coordinate of the new layer.compressionโ Compression method for the layer image data.opacityโ Opacity of the new layer (0-255).blend_modeโ Blend mode of the new layer, default isBlendMode.NORMAL.
Returns: The created PixelLayer (psd_tools.api.layers.PixelLayer) object.
property depth: int
Pixel depth bits ๐.
Returns: int
descendants(include_clip: bool = True) -> Iterator[Layer]
Return a generator to iterate over all descendant layers ๐ณ the whole family tree.
Parameters
include_clipโ Whether to include clipping layers. Default isTrue.
Example:
# Iterate over all layers
for layer in psd.descendants():
print(layer)
# Iterate over all layers in reverse order
for layer in reversed(list(psd.descendants())):
print(layer)
extend(layers: Iterable[Layer]) -> None
Add a list of layers to the end (top) of the group โฌ๏ธ.
This operation rewrites the internal references of the layers. and good news bestie: adding the same layer will not create a duplicate ๐ โโ๏ธ๐
Parameters
layersโ The layers to add.
Raises
TypeErrorโ If the provided object is not aLayerinstance.ValueErrorโ If attempting to add a group to itself.
find(name: str) -> Layer | None
Returns the first layer found for the given layer name ๐ first match wins, no cap.
Parameters
name
findall(name: str) -> Iterator[Layer]
Return a generator to iterate over all layers with the given name ๐ everybody with that name, step forward.
Parameters
name
classmethod frompil(image: Image, compression: Compression = Compression.RLE, color: int | float | Sequence[int | float] | None = None) -> Self
Create a new layer-less PSD document from a PIL Image ๐ฆ starting from scratch, but make it PSD.
Parameters
imageโ PIL Image object.compressionโ ImageData compression option. SeeCompression(psd_tools.constants.Compression).colorโ Background color for the compositing backdrop when saving. Accepts the same types asnew()color. When set,save()will composite layers against an opaque backdrop of this color.
Returns: A PSDImage (psd_tools.api.psd_image.PSDImage) object.
has_preview() -> bool
Returns if the document has real merged data ๐พ. When True, topil() returns pre-composed data. no extra work needed, periodt.
has_thumbnail() -> bool
True if the PSDImage has a thumbnail resource ๐ผ๏ธโจ.
property height: int
Document height ๐.
Returns: int
property image_resources: ImageResources
Document image resources ๐๏ธ. ImageResources (psd_tools.psd.image_resources.ImageResources) is a dict-like structure that keeps various document settings.
See psd_tools.constants.Resource (psd_tools.constants.Resource) for available keys ๐.
Returns: ImageResources (psd_tools.psd.image_resources.ImageResources)
Example:
from psd_tools.constants import Resource
version_info = psd.image_resources.get_data(Resource.VERSION_INFO)
slices = psd.image_resources.get_data(Resource.SLICES)
Image resources contain an ICC profile ๐ and here's literally how you export a PNG with the embedded ICC profile riding along:
from psd_tools.constants import Resource
icc_profile = psd.image_resources.get_data(Resource.ICC_PROFILE)
image = psd.compose(apply_icc=False)
image.save('output.png', icc_profile=icc_profile)
โจ index(layer: Layer) -> int
Returns the index of the specified layer in the group. where is it bestie ๐
Parameters
- layer โ The layer to find.
โจ insert(index: int, layer: Layer) -> None
Insert the given layer at the specified index.
Heads up tho: this operation rewrites the internal references of the layer. ๐ง
Parameters
- index โ The index to insert the layer at.
- layer โ The layer to insert.
Raises
TypeErrorโ If the provided object is not aLayerinstance.ValueErrorโ If attempting to add a group to itself.
โจ is_group() -> bool
Return True if this is a group. group chat behaviour fr fr ๐
โจ is_updated() -> bool
Returns whether the layer tree has been updated.
Returns
bool
โจ is_visible() -> bool
Returns visibility of the element. are we showing up or are we hiding ๐ญ
โจ kind: str
Kind.
Returns
'psdimage'
โจ left: int
Left coordinate.
Returns
0
โจ name: str
Element name.
Returns
'Root'
โจ new(mode: str, size: tuple[int, int], color: int | float | Sequence[int | float] = 0, depth: Literal[8, 16, 32] = 8, **kwargs: Any) -> Self
classmethod. Create a new PSD document. brand new blank canvas, main character energy โจ
Parameters
- mode โ The color mode to use for the new image.
- size โ A tuple containing
(width, height)in pixels. - color โ What color to use for the image. Default is black. Accepts a single integer (0-255 for 8-bit) or float in the
[0.0, 1.0]range, or a sequence of per-channel values using the same ranges (e.g., 3 values for"RGB", 4 for"CMYK"). Mixed int/float sequences are allowed. The color is used both as the initial image data fill and as thebackground_colorcompositing backdrop when saving. - depth โ Bit depth (8, 16, or 32).
Returns
A PSDImage object.
โจ numpy(channel: Literal['color', 'shape', 'alpha', 'mask'] | None = None) -> ndarray
Get NumPy array of the layer. numbers go brrr ๐ง
Parameters
- channel โ Which channel to return, can be
'color','shape','alpha', or'mask'. Default is'color+alpha'.
Returns
numpy.ndarray
โจ offset: tuple[int, int]
(left, top) tuple.
Returns
tuple
โจ open(fp: IO[bytes] | str | bytes | PathLike, max_alloc_bytes: int | None = None, **kwargs: Any) -> Self
classmethod. Open a PSD document. let us in bestie ๐ซถ
Parameters
- fp โ filename or file-like object.
- max_alloc_bytes โ optional per-document cap (bytes) on the buffer that
composite()/numpy()/topil()allocate from the declared geometry; rendering raisesValueErrorif the estimate exceeds it. Defaults to the$PSD_TOOLS_MAX_ALLOC_BYTESenv var (orpsd_tools.api.utils.MAX_ALLOC_BYTES) whenNone. - encoding โ charset encoding of the pascal string within the file, default
'macroman'. Some psd files need explicit encoding option.
Returns
A PSDImage object.
โจ parent: None
Parent of this layer.
โจ pil_mode: str
PIL mode of the document.
โจ pop(index: int = -1) -> Layer
Removes the specified layer from the list and returns it. gone but not forgotten ๐
This operation rewrites the internal references of the layer.
Parameters
- index โ The index of the layer to remove. Default is
-1(the last layer).
Raises
IndexErrorโ If the index is out of range.
Returns
The removed layer.
โจ remove(layer: Layer) -> Self
Removes the specified layer from the group.
This operation rewrites the internal references of the layer.
Parameters
- layer โ The layer to remove.
Raises
ValueErrorโ If the layer is not found in the group.
Returns
self
โจ right: int
Right coordinate.
Returns
int
โจ save(fp: IO[bytes] | str | bytes | PathLike, mode: str = 'wb', **kwargs: Any) -> None
Save the PSD file. Updates the ImageData section if the layer structure has been updated. lock it in ๐ฅ
Parameters
- fp โ filename or file-like object.
- encoding โ charset encoding of the pascal string within the file, default
'macroman'. - mode โ file open mode, default
'wb'.
โจ size: tuple[int, int]
(width, height) tuple.
Returns
tuple
โจ tagged_blocks: TaggedBlocks | None
Document tagged blocks that is a dict-like container of settings.
See psd_tools.constants.Tag for available keys.
Returns
TaggedBlocks or None.
Example:
from psd_tools.constants import Tag
patterns = psd.tagged_blocks.get_data(Tag.PATTERNS1)
โจ thumbnail() -> Image | None
Returns a thumbnail image in PIL.Image. When the file does not contain an embedded thumbnail image, returns None. no thumbnail = no vibes ๐ญ
โจ top: int
Top coordinate.
Returns
0
โจ topil(channel: int | ChannelID | None = None, apply_icc: bool = True) -> Image | None
Get PIL Image.
Parameters
- channel โ Which channel to return; e.g.,
0for'R'channel in RGB image. SeeChannelID. WhenNone, the method returns all the channels supported by PIL modes. - apply_icc โ Whether to apply ICC profile conversion to sRGB.
Returns
PIL.Image, or None if the composed image is not available.
โจ version: int
Document version. PSD file is 1, and PSB file is 2.
Returns
int
โจ viewbox: tuple[int, int, int, int]
Return bounding box of the viewport.
Returns
(left, top, right, bottom) tuple.
โจ visible: bool
Visibility.
Returns
True
โจ width: int
Document width.
Returns
int
๐ฆ psd_tools.api ๐ฆ
High-level API for working with PSD/PSB files.
This subpackage provides the user-facing API for psd-tools, offering Pythonic interfaces for manipulating Photoshop documents. It wraps the low-level psd_tools.psd binary structures with convenient methods and properties.
The main entry point is PSDImage, which provides document-level operations. Individual layers are represented by various layer classes in psd_tools.api.layers.
Key modules:
psd_tools.api.psd_image: MainPSDImageclass for document operationspsd_tools.api.layers: Layer type hierarchy (Layer,GroupMixin, etc.)psd_tools.api.adjustments: Adjustment layer typespsd_tools.api.mask: Layer mask operationspsd_tools.api.shape: Vector shape and stroke operationspsd_tools.api.effects: Layer effects (shadows, glows, etc.)psd_tools.api.pil_io: PIL/Pillow image I/O utilitiespsd_tools.api.numpy_io: NumPy array I/O utilities
Example usage:
from psd_tools import PSDImage
# Open a PSD file
psd = PSDImage.open('document.psd')
# Access layers
for layer in psd:
print(f"{layer.name}: {layer.kind}")
# Modify a layer
layer = psd[0]
layer.name = "New Name"
layer.opacity = 128
# Save changes
psd.save('modified.psd')
The API layer automatically reconstructs the layer tree from the flat list of layer records in the PSD file, establishing proper parent-child relationships for groups.
This module provides the high-level API for working with PSD files. It wraps the low-level psd_tools.psd structures with convenient Pythonic interfaces. Basically: the low-level stuff is giving raw bytes energy, and this module is here to make it actually cute to use. ๐
๐ PSDImage
class psd_tools.api.psd_image.PSDImage(data: psd_tools.psd.PSD)
A Photoshop PSD/PSB document, bestie. That's the whole vibe.
The low-level data structure is chillin' right there at PSDImage._record if you ever need to peek under the hood. โจ
Example โ look at her go:
from psd_tools import PSDImage
psdimage = PSDImage.open('example.psd')
image = psdimage.composite()
for layer in psdimage:
layer_image = layer.composite()
append(layer: psd_tools.api.layers.Layer) -> None
Add a layer to the end (top) of the group. Note that "end" here means the top of the stack, because PSD layer ordering has main character energy that way. ๐
This operation rewrites the internal references of the layer. Adding the same layer will not create a duplicate โ so no accidental clone situation, periodt.
Parameters
- layer โ The layer to add.
Raises
TypeErrorโ If the provided object is not aLayerinstance.ValueErrorโ If attempting to add a group to itself.
The "group to itself" one? Yeah, don't. That's a ValueError and also just emotionally complicated. ๐
property background_color: float | tuple[float, ...] | None
Background color for the merged composite image. Writable, so you can swap the vibe whenever.
When set, save() composites layers against an opaque backdrop of this color instead of a transparent one. Super useful for creating RGB-mode PSD files where transparent areas should show up as a specific color (e.g., white) in the merged composite. No more sad checkerboard reveal. ๐
Values live in the [0.0, 1.0] range, matching the composite() color parameter:
- RGB / Grayscale:
1.0= white,0.0= black - CMYK:
(0.0, 0.0, 0.0, 0.0)= white (no ink)
Use a scalar for uniform color or a tuple for per-channel values. Set to None for a transparent backdrop (that's the legacy behavior). Documents created via new() have this set automatically from the color parameter, so she comes pre-styled. ๐
Returns
float, tuple[float, ...], or None
Example:
psd = PSDImage.new('RGB', (640, 480), color=1.0)
psd.save('output.psd') # White background, 3 channels (no alpha)
property bbox: tuple[int, int, int, int]
Minimal bounding box that contains all the visible layers. Tight, minimal, no wasted space. ๐
Use viewbox to get the viewport bounding box instead. When the psd is empty, bbox is equal to the canvas bounding box.
Returns
(left, top, right, bottom) tuple.
property bottom: int
Bottom coordinate.
Returns
int
property channels: int
Number of color channels.
Returns
int
clear() -> None
Clears the group. Everything gone, poof, empty canvas energy. ๐ซง
This operation rewrites the internal references of the layers.
Returns
None
property color_mode: psd_tools.constants.ColorMode
Document color mode, such as 'RGB' or 'GRAYSCALE'. See psd_tools.constants.ColorMode for the whole roster. ๐
Returns
psd_tools.constants.ColorMode
property compatibility_mode: psd_tools.constants.CompatibilityMode
Set the compositing and layer organization compatibility mode. Writable.
This property checks whether the PSD file is compatible with specific authoring tools, such as Photoshop or CLIP Studio Paint. Different authoring tools may have different ways of handling layers โ like the use of clipping masks for groups โ and honestly they're all a little opinionated. The default is Photoshop compatibility mode.
Returns
psd_tools.constants.CompatibilityMode
composite()
composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray | None = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, ignore_preview: bool = False, apply_icc: bool = True) -> Image
Composite the PSD image. This is the moment, this is the main event. ๐ฅ
Parameters
- viewport โ Viewport bounding box specified by
(x1, y1, x2, y2)tuple. Default is theviewboxof the PSD. - ignore_preview โ Boolean flag to whether skip compositing when a pre-composited preview is available.
- force โ Boolean flag to force vector drawing.
- color โ Backdrop color specified by scalar or tuple of scalar. The color value should be in
[0.0, 1.0]. For example,(1., 0., 0.)specifies red in RGB color mode. - alpha โ Backdrop alpha in
[0.0, 1.0]. - layer_filter โ Callable that takes a layer as argument and returns whether if the layer is composited. Default is
is_visible().
Returns
PIL.Image.
count(layer: psd_tools.api.layers.Layer) -> int
Counts the number of occurrences of a layer in the group. Yes bestie, we're doing inventory. ๐งฎ
Parameters
- layer โ The layer to count.
create_group()
create_group(layer_list: Iterable[psd_tools.api.layers.Layer] | None = None, name: str = 'Group', opacity: int = 255, blend_mode: psd_tools.constants.BlendMode = BlendMode.PASS_THROUGH, open_folder: bool = True) -> psd_tools.api.layers.Group
Create a new group layer and add it to the PSDImage. Folder? Created. Organized? Iconic. ๐
Example:
group = psdimage.create_group(name='New Group')
group.append(psdimage.create_pixel_layer(image, name='Layer in Group'))
Parameters
- layer_list โ Optional list of layers to add to the group.
- name โ Name of the new group.
- opacity โ Opacity of the new layer (0-255).
- blend_mode โ Blend mode of the new layer, default is
BlendMode.PASS_THROUGH. - open_folder โ Whether the group is an open folder in the Photoshop UI.
Returns
The created psd_tools.api.layers.Group object.
create_pixel_layer()
create_pixel_layer(image: Image, name: str = 'Layer', top: int = 0, left: int = 0, compression: psd_tools.constants.Compression = Compression.RLE, opacity: int = 255, blend_mode: psd_tools.constants.BlendMode = BlendMode.NORMAL) -> psd_tools.api.layers.PixelLayer
Create a new pixel layer and add it to the PSDImage. Fresh pixels, just dropped. โจ
Example:
psdimage = PSDImage.new("RGB", (640, 480))
layer = psdimage.create_pixel_layer(image, name='Layer 1')
Parameters
- name โ Name of the new layer.
- image โ PIL Image object.
- top โ Top coordinate of the new layer.
- left โ Left coordinate of the new layer.
- compression โ Compression method for the layer image data.
- opacity โ Opacity of the new layer (0-255).
- blend_mode โ Blend mode of the new layer, default is
BlendMode.NORMAL.
Returns
The created psd_tools.api.layers.PixelLayer object.
property depth: int
Pixel depth bits.
Returns
int
descendants(include_clip: bool = True) -> Iterator[psd_tools.api.layers.Layer]
Return a generator to iterate over all descendant layers. The whole family tree, down to the tiniest grandchild layer. ๐ณ
Parameters
- include_clip โ Whether to include clipping layers. Default is
True.
Example:
# Iterate over all layers
for layer in psd.descendants():
print(layer)
# Iterate over all layers in reverse order
for layer in reversed(list(psd.descendants())):
print(layer)
extend(layers: Iterable[psd_tools.api.layers.Layer]) -> None
Add a list of layers to the end (top) of the group. Plural append, we're being efficient. ๐
This operation rewrites the internal references of the layers. Adding the same layer will not create a duplicate.
Parameters
- layers โ The layers to add.
Raises
TypeErrorโ If the provided object is not aLayerinstance.ValueErrorโ If attempting to add a group to itself.
find(name: str) -> psd_tools.api.layers.Layer | None
Returns the first layer found for the given layer name. First come, first served. ๐ซถ
Parameters
- name
findall(name: str) -> Iterator[psd_tools.api.layers.Layer]
Return a generator to iterate over all layers with the given name. Because duplicate layer names are absolutely a thing and we're not judging. ๐
Parameters
- name
classmethod frompil()
frompil(image: Image, compression: psd_tools.constants.Compression = Compression.RLE, color: int | float | Sequence[int | float] | None = None) -> Self
Create a new layer-less PSD document from PIL Image. Just you and the canvas โ no layers, no drama. ๐ฆ
Parameters
- image โ PIL Image object.
compressionโ the ImageData compression option, bestie. Go peepCompressionfor the deets. ๐ฅcolorโ the background color for the compositing backdrop when saving. Takes the exact same types asnew()'scolor. The moment you set it,save()will composite your layers against an opaque backdrop in that color. ๐
Returns โ a PSDImage object. Iconic. โจ
๐ has_preview() -> bool
Tells you if the document has real merged data. When it's True, topil() hands you pre-composed data instead of making you do the work. Slay. ๐ซถ
๐ has_thumbnail() -> bool
True if this PSDImage has a thumbnail resource. No thumbnail? Then it's False, simple as. ๐ธ
โญ property height: int
The document height, bestie.
Returns โ int
๐ฆ property image_resources: ImageResources
The document's image resources. ImageResources is a dict-like structure that keeps all your various document settings around.
See psd_tools.constants.Resource for the available keys. ๐
Returns โ ImageResources (psd_tools.psd.image_resources.ImageResources)
Example:
from psd_tools.constants import Resource
version_info = psd.image_resources.get_data(Resource.VERSION_INFO)
slices = psd.image_resources.get_data(Resource.SLICES)
Image resources also contain an ICC profile. The following shows how to export a PNG file with the ICC profile embedded โ noted, bestie, write it down:
from psd_tools.constants import Resource
icc_profile = psd.image_resources.get_data(Resource.ICC_PROFILE)
image = psd.compose(apply_icc=False)
image.save('output.png', icc_profile=icc_profile)
๐
index(layer: Layer) -> int
Returns the index of the specified layer inside the group. ๐
Parameters
layerโ the layer to find, bestie.
๐ insert(index: int, layer: Layer) -> None
Inserts the given layer at the specified index.
Heads up: this operation rewrites the internal references of the layer. It's not just vibes, it's structural. ๐
Parameters
indexโ the index to insert the layer at.layerโ the layer to insert.
Raises
TypeErrorโ if the object you handed over is not aLayerinstance.ValueErrorโ if you're attempting to add a group to itself. Don't do that. ๐
๐ง is_group() -> bool
Returns True if this is a group. Periodt.
๐ is_updated() -> bool
Tells you whether the layer tree has been updated, or not.
Returns โ bool
๐ is_visible() -> bool
Returns the visibility of the element. ๐
๐ property kind: str
The kind, bestie.
Returns โ 'psdimage'
โจ property left: int
The left coordinate.
Returns โ 0
๐ธ property name: str
The element name.
Returns โ 'Root'
๐ classmethod new(mode: str, size: tuple[int, int], color: int | float | Sequence[int | float] = 0, depth: Literal[8, 16, 32] = 8, **kwargs: Any) -> Self
Creates a brand new PSD document. Fresh start energy. ๐ฆ
Parameters
modeโ the color mode to use for the new image.sizeโ a tuple containing(width, height)in pixels.colorโ what color to use for the image. Default is black. Accepts a single integer (0-255for 8-bit) or a float in the[0.0, 1.0]range, or a sequence of per-channel values using the same ranges (e.g., 3 values for"RGB", 4 for"CMYK"). Mixed int/float sequences are allowed. The color is used both as the initial image data fill and as thebackground_colorcompositing backdrop when saving. ๐depthโ bit depth (8,16, or32).
Returns โ a PSDImage object. โจ
๐ซถ numpy(channel: Literal['color', 'shape', 'alpha', 'mask'] | None = None) -> ndarray
Gets you the NumPy array of the layer.
Parameters
channelโ which channel to return; can be'color','shape','alpha', or'mask'. Default is'color+alpha'.
Returns โ numpy.ndarray
โญ property offset: tuple[int, int]
The (left, top) tuple.
Returns โ tuple
๐ classmethod open(fp: IO[bytes] | str | bytes | PathLike, max_alloc_bytes: int | None = None, **kwargs: Any) -> Self
Opens a PSD document. Come on in, the water's fine. ๐
Parameters
fpโ filename or file-like object.max_alloc_bytesโ optional per-document cap (bytes) on the buffer thatcomposite()/numpy()/topil()allocate from the declared geometry; rendering raisesValueErrorif the estimate exceeds it. Defaults to the$PSD_TOOLS_MAX_ALLOC_BYTESenv var (orpsd_tools.api.utils.MAX_ALLOC_BYTES) whenNone. โ ๏ธencodingโ charset encoding of the pascal string within the file, default'macroman'. Some psd files need the explicitencodingoption, no cap.
Returns โ a PSDImage object.
๐ property parent: None
The parent of this layer. It's None, bestie โ root layers live parentless, main character energy. ๐
๐ property pil_mode: str
The PIL mode of the document.
๐ pop(index: int = -1) -> Layer
Removes the specified layer from the list and returns it. Popped and handed right back to you. ๐
This operation rewrites the internal references of the layer.
Parameters
indexโ the index of the layer to remove. Default is-1(the last layer).
Raises โ IndexError โ if the index is out of range.
Returns โ the removed layer.
๐ง remove(layer: Layer) -> Self
Removes the specified layer from the group.
This operation rewrites the internal references of the layer too. Same vibe asinsert()andpop().
Parameters
layerโ the layer to remove.
Raises โ ValueError โ if the layer is not found in the group.
Returns โ self
๐ property right: int
The right coordinate.
Returns โ int
โจ save(fp: IO[bytes] | str | bytes | PathLike, mode: str = 'wb', **kwargs: Any) -> None
Saves the PSD file. Updates the ImageData section if the layer structure has been updated. ๐พ
Parameters
fpโ filename or file-like object.encodingโ charset encoding of the pascal string within the file, default'macroman'.modeโ file open mode, default'wb'.
๐ฆ property size: tuple[int, int]
The (width, height) tuple.
Returns โ tuple
๐ธ property tagged_blocks: TaggedBlocks | None
Document tagged blocks, which is a dict-like container of settings.
See psd_tools.constants.Tag for the available keys.
Returns โ TaggedBlocks or None. It's literally tagging, bestie.
Example:
from psd_tools.constants import Tag
patterns = psd.tagged_blocks.get_data(Tag.PATTERNS1)
๐
thumbnail() -> Image | None
Returns a thumbnail image as a PIL.Image. When the file doesn't contain an embedded thumbnail image, it returns None. No thumbnail, no problem. ๐
โญ property top: int
The top coordinate.
Returns โ 0
๐ฅ topil(channel: int | ChannelID | None = None, apply_icc: bool = True) -> Image | None
Gets you a PIL Image.
Parameters
channelโ which channel to return; e.g.,0for the'R'channel in an RGB image. SeeChannelID. WhenNone, the method returns all the channels supported by PIL modes.apply_iccโ whether to apply ICC profile conversion to sRGB.
Returns โ PIL.Image, or None if the composed image is not available. ๐ญ
๐ property version: int
The document version. PSD file is 1, and PSB file is 2. iykyk. ๐
Returns โ int
๐ property viewbox: tuple[int, int, int, int]
Returns the bounding box of the viewport.
Returns โ (left, top, right, bottom) tuple.
๐ property visible: bool
Visibility.
Returns โ True
๐ซถ property width: int
The document width.
Returns โ int
For detailed layer types documentation, see psd_tools.api.layers. ๐
โจ psd_tools.api.adjustments โจ
Adjustment and fill layers. The little glow-up layers, bestie. ๐
Example:
if layer.kind == 'brightnesscontrast':
print(layer.brightness)
if layer.kind == 'gradientfill':
print(layer.gradient_kind)
๐ Fill layers ๐
So bestie, fill layers are basically ShapeLayer's cousin โ except this one might not have a vector mask attached at all. When that happens, the layer just spreads out and covers the whole entire canvas of the PSD document. Iconic behavior honestly. ๐
Every fill layer out there inherits from FillLayer.
Example, because we love a demo:
if isinstance(layer, psd_tools.layers.FillLayer):
image = layer.compose()
๐ SolidColorFill ๐
class psd_tools.api.adjustments.SolidColorFill(*args: Any)
Just a solid color fill. Simple. Clean. Gorgeous. โจ
Here's everything it comes with:
bbox:tuple[int, int, int, int]โ the(left, top, right, bottom)tuple, in that exact order, no cap.blend_mode:BlendModeโ the blend mode of this layer. It's writable, so go off.
Example:
from psd_tools.constants import BlendMode
if layer.blend_mode == BlendMode.NORMAL:
layer.blend_mode = BlendMode.SCREEN
Returns a BlendMode.
bottom:intโ the bottom coordinate.
Returns an int.
clip_layers:list[Self]โ the clip layers chillin' with this layer.
Returns a list of layers.
clipping:boolโ the clipping flag for this layer. Writable, so you can flip it.
Returns a bool.
clipping_layer:boolโ โ ๏ธ deprecated. Please use theclippingproperty instead, bestie, we're moving on.composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, apply_icc: bool = True) -> Image | Noneโ composites the layer AND the masks (that's the mask, the vector mask, and the clipping layers, all of it).
Parameters, okay:
- viewport โ the viewport bounding box, given as an
(x1, y1, x2, y2)tuple. Defaults to the layer'sbbox. - force โ boolean flag that forces vector drawing.
- color โ the backdrop color, as a scalar or a tuple of scalars. It lives in
[0.0, 1.0]. So like,(1., 0., 0.)is red in RGB color mode. - alpha โ the backdrop alpha, in
[0.0, 1.0]. - layer_filter โ a
Callablethat takes a layer as its argument and returns whether that layer gets composited or not. Default isis_visible().
Returns a PIL.Image.Image or None.
create_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Maskโ makes a pixel mask on this layer out of a PIL Image. ๐จ
If the image has an alpha channel (like RGBA or LA), that alpha channel becomes the mask data. If not, the image gets converted to grayscale (L mode). White (255) means fully unmasked, black (0) means fully masked. That's the whole vibe.
Parameters:
- image โ the source Image for the mask.
- top โ the top offset of the mask. Defaults to the layer's top.
- left โ the left offset of the mask. Defaults to the layer's left.
- compression โ the compression algorithm for the mask data.
Returns the new Mask.
Raises ValueError โ if the layer already has a mask. One mask only, we don't do duplicates. ๐
data:DescriptorBlockโ the color, inDescriptor(RGB).delete_layer() -> Selfโ deprecated, babe. Uselayer.parent.remove(layer)instead.effects:Effectsโ the layer effects.
Returns Effects.
fill_opacity:intโ the fill opacity of this layer, in the[0, 255]range. Writable.
Returns an int.
has_clip_layers(visible: bool = False) -> boolโ returnsTrueif the layer has clipping associated with it.
Parameters:
- visible โ if
True, it checks for visible clipping layers.
Returns a bool.
has_effects(enabled: bool = True, name: str | None = None) -> boolโ returnsTrueif the layer has effects.
Parameters:
- enabled โ if
True, checks for enabled effects. - name โ if you pass one, it checks for that specific effect type.
Returns a bool.
has_mask() -> boolโ returnsTrueif the layer has a mask.
Returns a bool.
has_origination() -> boolโ returnsTrueif the layer has live shape properties.
Returns a bool.
has_pixels() -> boolโ returnsTrueif the layer has pixels associated with it. When this one'sTrue, thetopilmethod hands you back aPIL.Image.Image.
Returns a bool.
has_stroke() -> boolโ returnsTrueif the shape has a stroke.has_vector_mask() -> boolโ returnsTrueif the layer has a vector mask.
Returns a bool.
height:intโ the height of the layer.
Returns an int.
is_group() -> boolโ returnsTrueif the layer is a group.
Returns a bool.
is_visible() -> boolโ the layer's visibility, and yes it takes group visibility into account too.
Returns a bool.
kind:strโ the kind of this layer, likegroup,pixel,shape,type,smartobject, orpsdimage. It's just the class name without thelayersuffix.
Returns a str.
layer_id:intโ the layer ID.
Returns an int layer id โ and if the layer never got assigned an id, you get -1.
left:intโ the left coordinate. Writable.
Returns an int.
lock(lock_flags: int = ProtectedFlags.COMPLETE) -> Noneโ locks a layer according to the combination of flags you hand it.
Parameters:
- lockflags โ an integer representing the locking state.
Example using the ProtectedFlags constants and a bitwise or operation to lock both pixels and positions:
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)
mask:Mask | Noneโ returns the mask associated with this layer.
Returns a Mask or None.
move_down(offset: int = 1) -> Selfโ moves the layer down by a certain offset, within the group that the layer is in.
Parameters:
- offset โ how many positions to move the layer down. It can be negative, go wild.
Raises:
ValueErrorโ if the layer has no parent, or the parent isn't a group.IndexErrorโ if the new index is out of bounds.
Returns self.
move_to_group(group: GroupMixin) -> Selfโ deprecated! Usegroup.append(layer)instead, bestie.
Parameters:
- group โ the group the current layer is gonna get moved into.
move_up(offset: int = 1) -> Selfโ moves the layer up by a certain offset, within the group that the layer is in.
Parameters:
- offset โ how many positions to move the layer up. Negative is allowed here too.
Raises:
ValueErrorโ if the layer has no parent, or the parent isn't a group.IndexErrorโ if the new index is out of bounds.
Returns self.
name:strโ the layer name. Writable.
Returns a str.
next_sibling(visible: bool = False) -> Self | Noneโ the next sibling of this layer. That's it, that's the whole thing.numpy(channel: str | None = None, real_mask: bool = True) -> ndarray | Noneโ grabs a NumPy array of the layer. ๐
Parameters:
- channel โ which channel you want. Your options are
'color','shape','alpha', or'mask'. Default is'color+alpha'.
Returns numpy.ndarray, or None if there's just no pixel there.
offset:tuple[int, int]โ the(left, top)tuple. Writable.
Returns a tuple.
opacity:intโ the opacity of this layer, in the[0, 255]range. Writable.
Returns an int.
origination:list[Origination]โ the property that gives you a list of live shapes, or a line.
Some vector masks have live shape properties associated with them โ that's the Photoshop feature for handling primitive shapes like a rectangle, an ellipse, or a line. Vector masks without live shape properties? Those are just plain path objects. No glow-up.
See psd_tools.api.shape.
Returns a list of Invalidated, Rectangle, RoundedRectangle, Ellipse, or Line.
parent:GroupMixinProtocol | Noneโ the parent of this layer.
โจ previous_sibling(visible: bool = False) -> Self | None
The previous sibling of this layer โ like, the layer that comes right before it in the same parent. Peek if you want bestie.
โจ reference_point โ tuple[float, float]
Reference point of this layer, handed to you as an (x, y) tuple in canvas coordinates. Writable, so go off ๐
The reference point is literally what transformations like rotation and scaling pivot around. That's it, that's the vibe.
Returns: an (x, y) tuple
โจ remove_mask() -> None
Yeet the pixel mask off this layer.
Raises ValueError โ if the layer doesn't even have a mask to begin with ๐ญ
โจ right โ int
Right coordinate.
Returns: int
โจ sheet_color โ SheetColorType
The color label of this layer, the one that shows up in the Photoshop layers panel. Writable, bestie.
Returns: SheetColorType
โจ size โ tuple[int, int]
The (width, height) tuple. Classic.
Returns: tuple
โจ stroke โ Stroke | None
Property for strokes. Simple as.
โจ tagged_blocks โ TaggedBlocks
Layer tagged blocks, which is a dict-like container of settings. It's giving little treasure chest of layer config ๐
See psd_tools.constants.Tag for which keys you can actually use.
Returns: TaggedBlocks
Example:
from psd_tools.constants import Tag
metadata = layer.tagged_blocks.get_data(Tag.METADATA_SETTING)
โจ top โ int
Top coordinate. Writable, no cap.
Returns: int
โจ topil(channel: int | None = None, apply_icc: bool = True) -> Image | None
Grab a PIL Image of the layer. This is the glow-up method fr fr โจ
Parameters
- channel โ which channel to hand back; e.g.,
0for the 'R' channel in an RGB image. SeeChannelID. When it'sNone, the method returns all the channels supported by PIL modes. - apply_icc โ whether to apply ICC profile conversion to sRGB.
Returns: PIL.Image.Image, or None if the layer has no pixels.
Example:
from psd_tools.constants import ChannelID
image = layer.topil()
red = layer.topil(ChannelID.CHANNEL_0)
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)
Note: not all of the PSD image modes are supported inPIL.Image.Image. For example, 'CMYK' mode cannot include an alpha channel in PIL. In that case,topildrops the alpha channel. ๐
โจ update_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Mask
Update the pixel mask of this layer with a new image. Mask makeover era ๐ง
If the image has an alpha channel (e.g. RGBA, LA), the alpha channel is used as the mask data. Otherwise the image is converted to grayscale (L mode). White (255) means fully unmasked, black (0) means fully masked.
Parameters
- image โ new source Image for the mask.
- top โ new top offset of the mask. Defaults to the current mask top.
- left โ new left offset of the mask. Defaults to the current mask left.
- compression โ compression algorithm for the mask data.
Returns: the updated Mask.
Raises ValueError โ if the layer does not have a mask. ๐
โจ vector_mask โ VectorMask | None
Returns the vector mask associated with this layer.
Returns: VectorMask or None
โจ visible โ bool
Layer visibility. Heads up โ this does not take group visibility into account. Writable.
Returns: bool
โจ width โ int
Width of the layer.
Returns: int
๐ฆ PatternFill
class psd_tools.api.adjustments.PatternFill(*args: Any)
Pattern fill. That's the whole vibe, bestie โ a fill made of pattern ๐ธ
โจ bbox โ tuple[int, int, int, int]
The (left, top, right, bottom) tuple.
โจ blend_mode โ BlendMode
Blend mode of this layer. Writable, icon behavior.
Example:
from psd_tools.constants import BlendMode
if layer.blend_mode == BlendMode.NORMAL:
layer.blend_mode = BlendMode.SCREEN
Returns: BlendMode.
โจ bottom โ int
Bottom coordinate.
Returns: int
โจ clip_layers โ list[Self]
Clip layers associated with this layer.
Returns: list of layers
โจ clipping โ bool
Clipping flag for this layer. Writable.
Returns: bool
โจ clipping_layer โ bool
Deprecated. Use the clipping property instead. ๐ (old news, bestie)
โจ composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, apply_icc: bool = True) -> Image | None
Composite the layer and its masks (the mask, vector mask, and clipping layers). This is where everything stacks up and slays ๐ฅ
Parameters
- viewport โ viewport bounding box specified by an
(x1, y1, x2, y2)tuple. Default is the layer's bbox. - force โ boolean flag to force vector drawing.
- color โ backdrop color specified by scalar or tuple of scalar. The color value should be in
[0.0, 1.0]. For example,(1., 0., 0.)specifies red in RGB color mode. - alpha โ backdrop alpha in
[0.0, 1.0]. - layer_filter โ callable that takes a layer as argument and returns whether the layer is composited. Default is
is_visible().
Returns: PIL.Image.Image or None.
โจ create_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Mask
Create a pixel mask on this layer from a PIL Image. Fresh mask, who dis ๐
If the image has an alpha channel (e.g. RGBA, LA), the alpha channel is used as the mask data. Otherwise the image is converted to grayscale (L mode). White (255) means fully unmasked, black (0) means fully masked.
Parameters
- image โ source Image for the mask.
- top โ top offset of the mask. Defaults to the layer's top.
- left โ left offset of the mask. Defaults to the layer's left.
- compression โ compression algorithm for the mask data.
Returns: the new Mask.
Raises ValueError โ if the layer already has a mask. ๐ญ one mask per layer, that's the rule.
โจ data โ DescriptorBlock
Pattern in Descriptor(PATTERN).
โจ delete_layer() -> Self
Deprecated: use layer.parent.remove(layer) instead. Bestie, the old way is giving ancient history ๐
โจ effects โ Effects
Layer effects.
Returns: Effects
โจ fill_opacity โ int
Fill opacity of this layer, in the [0, 255] range. Writable.
Returns: int
โจ has_clip_layers(visible: bool = False) -> bool
Returns True if the layer has associated clipping.
Parameters
- visible โ if
True, check for visible clipping layers.
Returns: bool
โจ has_effects(enabled: bool = True, name: str | None = None) -> bool
Returns True if the layer has effects. Sparkle check โจ
Parameters
- enabled โ if
True, check for enabled effects. - name โ if given, check for a specific effect type.
Returns: bool
โจ has_mask() -> bool
Returns True if the layer has a mask.
Returns: bool
โจ has_origination() -> bool
Returns True if the layer has live shape properties.
Returns: bool
โจ has_pixels() -> bool
Returns True if the layer has associated pixels. When this is True, the topil method returns a PIL.Image.Image.
Returns: bool
โจ has_stroke() -> bool
Returns True if the shape has a stroke.
โจ has_vector_mask() -> bool
Returns True if the layer has a vector mask.
Returns: bool
โจ height โ int
Height of the layer.
Returns: int
โจ is_group() -> bool
Return True if the layer is a group. Found family energy ๐ซถ
Returns: bool
โจ is_visible() -> bool
Layer visibility. This one does take group visibility into account. Periodt.
- Returns โ
boolโจ (that's the tail end of the property above, bestie, we're still in it ๐)
kind(property ยทstr) โ what vibe is this layer giving? Could begroup,pixel,shape,type,smartobject, orpsdimage๐ โ basically the class name with theLayersuffix chopped off.- Returns โ
str
- Returns โ
layer_id(property ยทint) โ the layer's ID number ๐ชช- Returns โ the
intlayer id. If the layer was never assigned an id, you get-1๐
- Returns โ the
left(property ยทint) โ left coordinate. Writable โ๏ธ- Returns โ
int
- Returns โ
lock(lock_flags: int = ProtectedFlags.COMPLETE) -> Noneโ locks a layer according to whatever combo of flags you hand it ๐- lockflags โ an integer representing the locking state
- Example using the constants of
ProtectedFlagsand the bitwise or operation to lock both pixels and positions:
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)
mask(property ยทMask|None) โ returns the mask associated with this layer ๐ญ- Returns โ
MaskorNone
- Returns โ
move_down(offset: int = 1) -> Selfโ moves the layer down by a certain offset within the group it lives in โฌ๏ธ- offset โ the number of positions to move the layer down (can be negative)
- Raises
ValueErrorโ if the layer has no parent, or its parent is not a group ๐ญIndexErrorโ if the new index is out of bounds ๐ฌ
- Returns โ
self
move_to_group(group: GroupMixin) -> Selfโ Deprecated: usegroup.append(layer)instead. โ ๏ธ- group โ the group the current layer will be moved into
move_up(offset: int = 1) -> Selfโ moves the layer up by a certain offset within the group it lives in โฌ๏ธ- offset โ the number of positions to move the layer up (can be negative)
- Raises
ValueErrorโ if the layer has no parent, or its parent is not a group ๐ญIndexErrorโ if the new index is out of bounds ๐ฌ
- Returns โ
self
name(property ยทstr) โ the layer name. Writable โ๏ธ- Returns โ
str
- Returns โ
next_sibling(visible: bool = False) -> Self | Noneโ the next sibling of this layer, iykyk ๐ฏnumpy(channel: str | None = None, real_mask: bool = True) -> ndarray | Noneโ hands you a NumPy array of the layer ๐งฎ- channel โ which channel to return; can be
'color','shape','alpha', or'mask'. Default is'color+alpha' - Returns โ
numpy.ndarray, orNoneif there's no pixel ๐
- channel โ which channel to return; can be
offset(property ยทtuple[int, int]) โ a(left, top)tuple. Writable โ๏ธ- Returns โ
tuple
- Returns โ
opacity(property ยทint) โ opacity of this layer, in the[0, 255]range. Writable โ๏ธ- Returns โ
int
- Returns โ
origination(property ยทlist[Origination]) โ property for a list of live shapes or a line ๐ฆโญ- Some of the vector masks have associated live shape properties โ that's the Photoshop feature for handling primitive shapes like a rectangle, an ellipse, or a line. Vector masks without live shape properties are plain path objects.
- See
psd_tools.api.shape. - Returns โ a list of
Invalidated,Rectangle,RoundedRectangle,Ellipse, orLine.
parent(property ยทGroupMixinProtocol | None) โ the parent of this layer ๐ซถprevious_sibling(visible: bool = False) -> Self | Noneโ the previous sibling of this layer ๐ฏreference_point(property ยทtuple[float, float]) โ the reference point of this layer as an(x, y)tuple in canvas coordinates. Writable โ๏ธ- The reference point is what gets used for transformations like rotation and scaling ๐
- Returns โ an
(x, y)tuple
remove_mask() -> Noneโ removes the pixel mask from this layer ๐งน- Raises
ValueErrorโ if the layer doesn't have a mask
- Raises
right(property ยทint) โ right coordinate โก๏ธ- Returns โ
int
- Returns โ
sheet_color(property ยทSheetColorType) โ the color label of this layer in the Photoshop layers panel. Writable โ๏ธ- Returns โ
SheetColorType
- Returns โ
size(property ยทtuple[int, int]) โ a(width, height)tuple ๐- Returns โ
tuple
- Returns โ
stroke(property ยทStroke|None) โ property for strokes ๐๏ธtagged_blocks(property ยทTaggedBlocks) โ layer tagged blocks, which is a dict-like container of settings ๐๏ธ- See
psd_tools.constants.Tagfor the available keys. - Returns โ
TaggedBlocks - Example:
- See
from psd_tools.constants import Tag
metadata = layer.tagged_blocks.get_data(Tag.METADATA_SETTING)
top(property ยทint) โ top coordinate. Writable โ๏ธ- Returns โ
int
- Returns โ
topil(channel: int | None = None, apply_icc: bool = True) -> Image | Noneโ hands you a PIL Image of the layer ๐ผ๏ธ- channel โ which channel to return; e.g.
0for the'R'channel in an RGB image. SeeChannelID. When it'sNone, the method returns all the channels supported by PIL modes. - apply_icc โ whether to apply ICC profile conversion to sRGB ๐จ
- Returns โ
PIL.Image.Image, orNoneif the layer has no pixels - Example:
- channel โ which channel to return; e.g.
from psd_tools.constants import ChannelID
image = layer.topil()
red = layer.topil(ChannelID.CHANNEL_0)
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)
- Note: not all of the PSD image modes are supported in
PIL.Image.Image. For example,'CMYK'mode can't include an alpha channel in PIL. In this case,topildrops the alpha channel ๐ซ
update_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Maskโ updates the pixel mask of this layer with a brand new image ๐- If the image has an alpha channel (e.g.
RGBA,LA), that alpha channel is used as the mask data. Otherwise the image gets converted to grayscale (Lmode). White (255) means fully unmasked, black (0) means fully masked ๐ค๐ค - image โ new source Image for the mask
- top โ new top offset of the mask. Defaults to the current mask top
- left โ new left offset of the mask. Defaults to the current mask left
- compression โ compression algorithm for the mask data
- Returns โ the updated
Mask - Raises
ValueErrorโ if the layer doesn't have a mask ๐ญ
- If the image has an alpha channel (e.g.
vector_mask(property ยทVectorMask|None) โ returns the vector mask associated with this layer โจ- Returns โ
VectorMaskorNone
- Returns โ
visible(property ยทbool) โ layer visibility. Heads up: this does not take group visibility into account ๐. Writable โ๏ธ- Returns โ
bool
- Returns โ
width(property ยทint) โ width of the layer ๐- Returns โ
int
- Returns โ
๐ญ GradientFill
class psd_tools.api.adjustments.GradientFill(*args: Any)
Gradient fill, bestie ๐ โ the exact kind of gradient moment that makes a design pop.
bbox(property ยทtuple[int, int, int, int]) โ a(left, top, right, bottom)tuple ๐ฆblend_mode(property ยทBlendMode) โ blend mode of this layer. Writable โ๏ธ- Example:
from psd_tools.constants import BlendMode
if layer.blend_mode == BlendMode.NORMAL:
layer.blend_mode = BlendMode.SCREEN
- Returns โ
BlendMode
bottom(property ยทint) โ bottom coordinate โฌ๏ธ- Returns โ
int
- Returns โ
clip_layers(property ยทlist[Self]) โ clip layers associated with this layer โ๏ธ- Returns โ list of layers
clipping(property ยทbool) โ clipping flag for this layer. Writable โ๏ธ- Returns โ
bool
- Returns โ
clipping_layer(property ยทbool) โ Deprecated. Use theclippingproperty instead. โ ๏ธ
๐ซถ composite(...) โ the group-hug method
composite(viewport: tuple[int, int, int, int] | None = None,
force: bool = False, color: float | tuple[float, ...] | ndarray =
1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None
= None, apply_icc: bool = True) -> Image | None
This one composites layers and masks โ like, all of them: the mask, the vector mask, and the clipping layers. It's the whole squad showing up for the group photo. ๐ธ
Parameters
viewportโ the viewport bounding box, handed over as an(x1, y1, x2, y2)tuple. Default is the layer's bbox, obviously. ๐forceโ a boolean flag that forces vector drawing. Yes queen, draw it anyway. โจcolorโ the backdrop color, given as a scalar or a tuple of scalars. The color value lives in[0.0, 1.0]. For example,(1., 0., 0.)is red in RGB color mode. So specific, so iconic. ๐alphaโ the backdrop alpha, in[0.0, 1.0].layer_filterโ aCallablethat takes a layer as its argument and returns whether that layer gets composited. Default isis_visible().
Returns
PIL.Image.Image or None.
๐ create_mask(...) โ build a pixel mask out of a PIL Image
create_mask(image: Image, top: int | None = None, left: int | None = None,
compression: Compression = Compression.RLE) -> Mask
Creates a pixel mask on this layer, sourced from a PIL Image. Lowkey magic.
If your image has an alpha channel (think RGBA, LA), then that alpha channel is used as the mask data. No alpha? Then the image gets converted to grayscale (L mode). And the vibes are: white (255) means fully unmasked, black (0) means fully masked. That's the whole scale, bestie. ๐ค๐ค
Parameters
imageโ the Source Image for the mask.topโ top offset of the mask. Defaults to the layer's top.leftโ left offset of the mask. Defaults to the layer's left.compressionโ the compression algorithm used for the mask data.
Returns
The brand-new Mask. โจ
Raises
ValueErrorโ if the layer already has a mask. (One mask per layer, babes, that's the rule.)
๐ property data: DescriptorBlock
Gradient in Descriptor(GRADIENT). That's the whole thing โ she's a DescriptorBlock.
๐ delete_layer() -> Self
Deprecated: use layer.parent.remove(layer) instead. The old way, the flop way. Go use the new one. ๐
๐ property effects: Effects
The layer effects.
Returns
Effects
โญ property fill_opacity: int
Fill opacity of this layer, in the [0, 255] range. Writable, so go ahead and tweak her.
Returns
int
๐ property gradient_kind: str
The kind of gradient. It's exactly one of these, no in-between:
LinearRadialAngleReflectedDiamond
๐
has_clip_layers(visible: bool = False) -> bool
Returns True if the layer has associated clipping.
Parameters
visibleโ ifTrue, it checks specifically for visible clipping layers.
Returns
bool
โจ has_effects(enabled: bool = True, name: str | None = None) -> bool
Returns True if the layer has effects. She's got the glow-up, fr.
Parameters
enabledโ ifTrue, check for enabled effects.nameโ if given, check for a specific effect type.
Returns
bool
๐ฆ has_mask() -> bool
Returns True if the layer has a mask.
Returns
bool
๐ธ has_origination() -> bool
Returns True if the layer has live shape properties.
Returns
bool
๐ has_pixels() -> bool
Returns True if the layer has associated pixels. And when this is True, the topil method returns PIL.Image.Image. Noted, bestie. ๐
Returns
bool
๐ง has_stroke() -> bool
Returns True if the shape has a stroke. Outlined and unbothered. ๐
๐ has_vector_mask() -> bool
Returns True if the layer has a vector mask.
Returns
bool
โญ property height: int
Height of the layer.
Returns
int
๐ซถ is_group() -> bool
Returns True if the layer is a group. Your little found family. ๐ก
Returns
bool
๐ is_visible() -> bool
Layer visibility. And here's the thing โ it takes group visibility into account. So if the group is hidden, her whole bloodline is hidden. Periodt.
Returns
bool
๐ property kind: str
The kind of this layer, such as group, pixel, shape, type, smartobject, or psdimage. Basically the class name without the layer suffix. Love a consistent naming scheme. โจ
Returns
str
๐
property layer_id: int
The layer ID.
Returns
int layer id โ but if the layer was never assigned an id, you get -1. Sad, but valid.
๐ property left: int
Left coordinate. Writable.
Returns
int
๐ lock(lock_flags: int = ProtectedFlags.COMPLETE) -> None
Locks a layer according to the combination of flags you pass. (The param is listed as lockflags in the signature docs โ same thing, don't @ me.)
Parameters
lockflagsโ an integer representing the locking state.
Example โ using the constants of ProtectedFlags and a bitwise or operation to lock both pixels and positions:
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)
No one's moving her. Not today. ๐
๐ฆ property mask: Mask | None
Returns the mask associated with this layer.
Returns
Mask or None
๐ธ move_down(offset: int = 1) -> Self
Moves the layer down a certain offset within the group the layer is in. She's stepping back, respectfully.
Parameters
offsetโ the number of positions to move the layer down (and yes, it can be negative).
Raises
ValueErrorโ if the layer has no parent, or if the parent is not a group.IndexErrorโ if the new index is out of bounds.
Returns
self
๐ move_to_group(group: GroupMixin) -> Self
Deprecated: use group.append(layer) instead. Stop using the old one, I'm begging. ๐
Parameters
groupโ the group the current layer will be moved into.
๐ move_up(offset: int = 1) -> Self
Moves the layer up a certain offset within the group the layer is in. Main character ascension arc. ๐
Parameters
offsetโ the number of positions to move the layer up (can be negative).
Raises
ValueErrorโ if the layer has no parent, or if the parent is not a group.IndexErrorโ if the new index is out of bounds.
Returns
self
โญ property name: str
Layer name. Writable, so go name her something gorgeous.
Returns
str
๐ next_sibling(visible: bool = False) -> Self | None
Next sibling of this layer. Simple as that. ๐ซถ
๐ง numpy(channel: str | None = None, real_mask: bool = True) -> ndarray | None
Gets you a NumPy array of the layer. Nerd mode: activated. ๐คโจ
Parameters
channelโ which channel to return. Can be'color','shape','alpha', or'mask'. Default is'color+alpha'.
Returns
numpy.ndarray, or None if there's no pixel.
๐ธ property offset: tuple[int, int]
(left, top) tuple. Writable.
Returns
tuple
๐ property opacity: int
Opacity of this layer, in the [0, 255] range. Writable. Turn the drama all the way up or all the way down.
Returns
int
๐ property origination: list[Origination]
A property for a list of live shapes, or a line.
Some of the vector masks have associated live shape properties, which are a Photoshop feature for handling primitive shapes like a rectangle, an ellipse, or a line. Vector masks without live shape properties are just plain path objects. Simple as.
See psd_tools.api.shape.
Returns
A list of Invalidated, Rectangle, RoundedRectangle, Ellipse, or Line.
๐ property parent: GroupMixinProtocol | None
Parent of this layer. Your layer's layer-mom. ๐ฅบ
๐ฆ previous_sibling(visible: bool = False) -> Self | None
Previous sibling of this layer. The one before her, iykyk.
โญ property reference_point: tuple[float, float]
The reference point of this layer, as an (x, y) tuple in the canvas coordinates. Writable.
The reference point is what gets used for transformations like rotation and scaling โ it's the little anchor everything pivots around. ๐
Returns
(x, y) tuple
๐ remove_mask() -> None
Removes the pixel mask from this layer. Gone. Deleted. Not coming back. โ๏ธ
Raises
ValueErrorโ if the layer does not have a mask. (Can't remove what was never there, bestie.)
๐ property right: int
Right coordinate.
Returns
int
๐ property sheet_color: SheetColorType
The color label of this layer in the Photoshop layers panel. Writable โ yes, you can repaint the tab. ๐จ
Returns
SheetColorType
๐ธ property size: tuple[int, int]
(width, height) tuple.
Returns
tuple
๐ property stroke: Stroke | None
A property for strokes.
๐ tagged_blocks
property tagged_blocks: TaggedBlocks
Bestie, this is the layer's tagged blocks โ literally a dict-like lil container stuffed with settings. ๐
Wanna know what keys you can pull from it? Go peek at psd_tools.constants.Tag.
Returns: TaggedBlocks โ psd_tools.psd.tagged_blocks.TaggedBlocks
Example, because we love a demo:
from psd_tools.constants import Tag
metadata = layer.tagged_blocks.get_data(Tag.METADATA_SETTING)
๐ top
property top: int
Top coordinate. And yes, she's writable โ go off. โจ
Returns: int
๐ผ๏ธ topil
topil(channel: int | None = None, apply_icc: bool = True) -> Image | None
Okay so this is the one that gets you an actual PIL Image of the layer. Main character behavior fr.
Parameters:
channelโ which channel do you want back? Like,0gives you the'R'channel in an RGB image. Seepsd_tools.constants.ChannelID. PassNoneand the method hands you back all the channels that PIL modes support.apply_iccโ whether to apply ICC profile conversion to sRGB. ๐
Returns: PIL.Image.Image, or None if the layer has no pixels. (no pixels = no vibes, sorry)
Example:
from psd_tools.constants import ChannelID
image = layer.topil()
red = layer.topil(ChannelID.CHANNEL_0)
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)
Note: not all PSD image modes are supported byPIL.Image.Image. Like,'CMYK'mode can't hold an alpha channel in PIL, periodt. So in that casetopiljust drops the alpha channel. ๐ซ
๐ญ update_mask
update_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Mask
Swap the pixel mask of this layer for a brand new image. Iconic.
If your image has an alpha channel (think RGBA, LA), that alpha channel becomes the mask data. No alpha? Then the image gets converted to grayscale (L mode). White (255) = fully unmasked ๐, black (0) = fully masked ๐ค.
Parameters:
imageโ the new source Image for the mask.topโ new top offset of the mask. Defaults to the current mask top.leftโ new left offset of the mask. Defaults to the current mask left.compressionโ compression algorithm for the mask data.
Returns: the updated Mask โ psd_tools.api.mask.Mask
Raises ValueError โ if the layer doesn't have a mask. No mask, no update, that's just the rules bestie. ๐ญ
๐ฆ vector_mask
property vector_mask: VectorMask | None
Returns the vector mask associated with this layer.
Returns: VectorMask โ psd_tools.api.shape.VectorMask, or None
๐ visible
property visible: bool
Layer visibility. Heads up tho: this does not take group visibility into account. Writable.
Returns: bool
๐ width
property width: int
Width of the layer. Just the number, no drama.
Returns: int
โจ Adjustment layers โจ
So, adjustment layers apply image filtering to the composed result. Every single adjustment layer inherits from AdjustmentLayer.
Here's the thing: adjustment layers do not have pixels, and they're currently ignored in compose. So if you try to call topil on one, you always get None back. Not a bug, just how she is. ๐
But just like any other layer, adjustment layers might have an associated mask or vector mask. And an adjustment can show up in other layers' clipping layers too. iykyk.
Example:
if isinstance(layer, psd_tools.layers.AdjustmentLayer):
print(layer.kind)
๐๏ธ BrightnessContrast
class psd_tools.api.adjustments.BrightnessContrast(*args: Any)
Brightness and contrast adjustment.
property automatic: boolproperty brightness: intproperty contrast: intproperty lab: boolproperty mean: intproperty use_legacy: boolproperty vrsn: int
๐ Curves
class psd_tools.api.adjustments.Curves(*args: Any)
Curves adjustment.
property data: Curves
Raw data.
Returns: Curves
property extra: Any
โ๏ธ Exposure
class psd_tools.api.adjustments.Exposure(*args: Any)
Exposure adjustment.
property exposure: float
Exposure.
Returns: float
property exposure_offset: float
Exposure offset.
Returns: float
property gamma: float
Gamma.
Returns: float
๐๏ธ Levels
class psd_tools.api.adjustments.Levels(*args: Any)
Levels adjustment.
Levels contain a list of LevelRecord. Yes bestie, a whole list.
property data: Levels
List of level records. The first record is the master. ๐
Returns: Levels.
property master: LevelRecord
Master record.
๐บ Vibrance
class psd_tools.api.adjustments.Vibrance(*args: Any)
Vibrance adjustment.
property saturation: int
Saturation.
Returns: int
property vibrance: int
Vibrance.
Returns: int
๐ HueSaturation
class psd_tools.api.adjustments.HueSaturation(*args: Any)
Hue/Saturation adjustment.
HueSaturation contains a list of data. ๐
property colorization: tuple
Colorization.
Returns: tuple
property data: list
List of Hue/Saturation records.
Returns: list
property enable_colorization: int
Enable colorization.
Returns: int
property master: tuple
Master record.
Returns: tuple
โ๏ธ ColorBalance
class psd_tools.api.adjustments.ColorBalance(*args: Any)
Color balance adjustment.
property highlights: tuple
Highlights.
Returns: tuple
property luminosity: int
Luminosity.
Returns: int
property midtones: tuple
Mid-tones.
Returns: tuple
property shadows: tuple
Shadows.
Returns: tuple
๐ค๐ค BlackAndWhite
class psd_tools.api.adjustments.BlackAndWhite(*args: Any)
Black and white adjustment.
property blue: intproperty cyan: intproperty green: intproperty magenta: intproperty preset_file_name: strproperty preset_kind: intproperty red: intproperty tint_color: Anyproperty use_tint: boolproperty yellow: int
๐ธ PhotoFilter
class psd_tools.api.adjustments.PhotoFilter(*args: Any)
Photo filter adjustment.
property color_components: Anyproperty color_space: Anyproperty density: Anyproperty luminosity: Any
property xyz: bool
xyz.
Returns: bool
๐ ChannelMixer
class psd_tools.api.adjustments.ChannelMixer(*args: Any)
Channel mixer adjustment.
property data: Anyproperty monochrome: Any
๐ ColorLookup
class psd_tools.api.adjustments.ColorLookup(*args: Any)
Color lookup adjustment.
๐จ Posterize
class psd_tools.api.adjustments.Posterize(*args: Any)
Posterize adjustment.
property posterize: int
Posterize value.
Returns: int
๐ช Threshold
class psd_tools.api.adjustments.Threshold(*args: Any)
Threshold adjustment.
property threshold: int
Threshold value.
Returns: int
๐ฏ SelectiveColor
class psd_tools.api.adjustments.SelectiveColor(*args: Any)
Selective color adjustment.
property data: Anyproperty method: Any
๐ GradientMap
class psd_tools.api.adjustments.GradientMap(*args: Any)
Gradient map adjustment.
property color_model: Anyproperty color_stops: Anyproperty dithered: Anyproperty expansion: Anyproperty gradient_name: Any
property interpolation: float
Interpolation between 0.0 and 1.0.
property length: Anyproperty max_color: Anyproperty min_color: Anyproperty mode: Anyproperty random_seed: Anyproperty reversed: Anyproperty roughness: Anyproperty show_transparency: Anyproperty transparency_stops: Anyproperty use_vector_color: Any
๐ซ psd_tools.api.effects
Effects module. Slay.
class psd_tools.api.effects.Effects(layer: LayerProtocol)
List-like effects.
Only present effects are kept. If it's not there, it's not there. ๐
property enabled: bool
Whether if all the effects are enabled.
Return type: bool
find(name: str, enabled: bool = True) -> Iterator[_Effect]
Iterate effect items by name.
Parameters:
nameโ Effect name, e.g.DropShadow,InnerShadow,OuterGlow,InnerGlow,ColorOverlay,GradientOverlay,PatternOverlay,Stroke,BevelEmboss, orSatin.enabledโ If true, only return enabled effects.
Return type: Iterator[Effect] โ psd_tools.terminology.Key.Effect
property scale: float
Scale value.
๐ฆ DropShadow
bestie, say hi to DropShadow โ the psd_tools.api.effects baddie that makes your layer look like it's floating above everything else. main character energy fr fr. its constructor takes a descriptor and an image_resources:
class psd_tools.api.effects.DropShadow(descriptor: Descriptor, image_resources: ImageResources)
(and just so you know where those live: Descriptor is psd_tools.psd.descriptor.Descriptor and ImageResources is psd_tools.psd.image_resources.ImageResources โ noted once, applies everywhere below ๐
)
properties
anglefloat โ the angle value ๐anti_aliasedbool โ anti-aliased (the docs literally spell it "Angi-aliased", iconic typo, but the meaning is anti-aliased โจ)blend_modebytes โ the effect blending modechokefloat โ choke level, in pixelscolorDescriptor โ the color ๐จcontourDescriptor โ the contour configurationdistancefloat โ distance, in pixelsenabledbool โ whether the effect is enabledlayer_knocks_outbool โ layers are knocking outnamestr โ the effect namenoisefloat โ noise level, in percentopacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIshownbool โ whether the effect is shown in the dialogsizefloat โ size, in pixelsuse_global_lightbool โ using global lightvalueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead, okay?
๐ฉท InnerShadow
the shy sibling of DropShadow โ same energy, but it does its thing inside the layer. lowkey dramatic, highkey gorgeous. constructor:
class psd_tools.api.effects.InnerShadow(descriptor: Descriptor, image_resources: ImageResources)
properties
anglefloat โ the angle value ๐anti_aliasedbool โ angi-aliased ๐blend_modebytes โ the effect blending modechokefloat โ choke level, in pixelscolorDescriptor โ the colorcontourDescriptor โ the contour configurationdistancefloat โ distance, in pixelsenabledbool โ whether the effect is enablednamestr โ the effect namenoisefloat โ noise level, in percentopacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIshownbool โ whether the effect is shown in the dialogsizefloat โ size, in pixelsuse_global_lightbool โ using global lightvalueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead
ngl, notice how InnerShadow has no layer_knocks_out? that one's DropShadow-exclusive. don't go looking for it, it's not there ๐
โจ OuterGlow
the glow that goes AROUND your layer, like a halo but make it fashion. constructor:
class psd_tools.api.effects.OuterGlow(descriptor: Descriptor, image_resources: ImageResources)
properties
anglefloat โ the angle valueanti_aliasedbool โ angi-aliased (again ๐ญ)blend_modebytes โ the effect blending modechokefloat โ choke level, in pixelscolorDescriptor โ the colorcontourDescriptor โ the contour configurationditheredbool โ the dither flagenabledbool โ whether the effect is enabledglow_typebytes โ glow typegradientDescriptor โ gradient configurationnamestr โ the effect namenoisefloat โ noise level, in percentoffsetDescriptor โ offset value, in a Pnt descriptoropacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIquality_jitterfloat โ quality jitter, in percentquality_rangefloat โ quality range, in percentreversedbool โ reverse flagshownbool โ whether the effect is shown in the dialogsizefloat โ size, in pixelsspreadfloat โ spread level, in percenttypebytes โ gradient type, one oflinear,radial,angle,reflected, ordiamond๐ซvalueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead
๐ธ InnerGlow
the inside-job glow. same glow energy, but it stays home. constructor:
class psd_tools.api.effects.InnerGlow(descriptor: Descriptor, image_resources: ImageResources)
properties
anglefloat โ the angle valueanti_aliasedbool โ angi-aliased ๐ซblend_modebytes โ the effect blending modechokefloat โ choke level, in pixelscolorDescriptor โ the colorcontourDescriptor โ the contour configurationditheredbool โ the dither flagenabledbool โ whether the effect is enabledglow_sourcebytes โ elements sourceglow_typebytes โ glow typegradientDescriptor โ gradient configurationnamestr โ the effect namenoisefloat โ noise level, in percentoffsetDescriptor โ offset value, in a Pnt descriptoropacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIquality_jitterfloat โ quality jitter, in percentquality_rangefloat โ quality range, in percentreversedbool โ reverse flagshownbool โ whether the effect is shown in the dialogsizefloat โ size, in pixelstypebytes โ gradient type, one oflinear,radial,angle,reflected, ordiamond๐ซvalueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead
bestie, spot the difference: InnerGlow hasglow_sourceand OuterGlow hasspread. they are NOT the same girl. iykyk ๐
๐ ColorOverlay
just straight-up painting your layer a new color. simple, effective, slays every time. constructor:
class psd_tools.api.effects.ColorOverlay(descriptor: Descriptor, image_resources: ImageResources)
properties
blend_modebytes โ the effect blending modecolorDescriptor โ the colorenabledbool โ whether the effect is enablednamestr โ the effect nameopacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIshownbool โ whether the effect is shown in the dialogvalueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead
eight properties, zero drama. ColorOverlay said "I keep it simple" and honestly? respect ๐
๐ GradientOverlay
ColorOverlay's louder cousin โ instead of one flat color you get a whole gradient situation. constructor:
class psd_tools.api.effects.GradientOverlay(descriptor: Descriptor, image_resources: ImageResources)
properties
alignedbool โ alignedanglefloat โ the angle valueblend_modebytes โ the effect blending modeditheredbool โ the dither flagenabledbool โ whether the effect is enabledgradientDescriptor โ gradient configurationnamestr โ the effect nameoffsetDescriptor โ offset value, in a Pnt descriptoropacityfloat โ layer effect opacity, in percentagepresentbool โ whether the effect is present in the Photoshop UIreversedbool โ reverse flagscalefloat โ the scale valueshownbool โ whether the effect is shown in the dialogtypebytes โ gradient type, one oflinear,radial,angle,reflected, ordiamond๐valueDescriptor โ โ ๏ธ DEPRECATED ๐ โ effect descriptor value. use thedescriptorproperty instead
๐ง PatternOverlay
and last one for this batch โ patterns instead of colors or gradients. texture girlies, this is your moment. constructor:
class psd_tools.api.effects.PatternOverlay(descriptor: Descriptor, image_resources: ImageResources)
properties
alignedbool โ alignedanglefloat โ the angle valueblend_modebytes โ the effect blending mode
and that's where we're picking back up next part, bestie โ more PatternOverlay properties incoming, don't go anywhere ๐
enabled:boolโ is this effect even on, bestie? yes/no, that's the whole vibe check.linked:boolโ linked. that's it. that's the tea. ๐name:strโ the effect's name, obviously.opacity:floatโ layer effect opacity, measured in percentage.pattern:Descriptorโ the pattern config,psd_tools.psd.descriptor.Descriptorstyle.phase:Descriptorโ phase value in Point. yes, Point with a capital P, iconic.present:boolโ does this effect show up in the Photoshop UI? that's the question.scale:floatโ scale value. ๐ฆshown:boolโ whether the effect is shown in the dialog.value:Descriptorโ deprecated, bestie, do NOT build your whole personality on this one.
Effect descriptor value. Use thedescriptorproperty instead. like genuinely, usedescriptor.
Stroke
class psd_tools.api.effects.Stroke(descriptor: Descriptor, image_resources: ImageResources)
okay so a stroke is justโฆ an outline around your layer, and the way this class is giving so much detail about it โจ here's everything it exposes:
angle:floatโ angle value.blend_mode:bytesโ effect blending mode.color:Descriptorโ color. theDescriptorispsd_tools.psd.descriptor.Descriptor, no cap.dithered:boolโ dither flag. ๐enabled:boolโ whether if the effect is enabled.fill_type:bytesโ the fill type:SolidColor,Gradient, orPattern.gradient:Descriptorโ gradient configuration.linked:boolโ linked.name:strโ effect name.offset:Descriptorโ offset value, sitting inside a Pnt descriptor.opacity:floatโ layer effect opacity in percentage.overprint:boolโ overprint flag.pattern:Descriptorโ pattern config.phase:Descriptorโ phase value in Point.position:bytesโ where the stroke sits:InsetFrame,OutsetFrame, orCenteredFrame. pick your fighter ๐present:boolโ whether if the effect is present in Photoshop UI.reversed:boolโ reverse flag.shown:boolโ whether if the effect is shown in dialog.size:floatโ size value.type:bytesโ gradient type, and it's one oflinear,radial,angle,reflected, ordiamond.value:Descriptorโ deprecated!!
Effect descriptor value. Use descriptor property instead. seriously bestie, the deprecated one is not the serve.
BevelEmboss
class psd_tools.api.effects.BevelEmboss(descriptor: Descriptor, image_resources: ImageResources)
the lil 3D-look effect, and the property list is lowkey enormous, buckle up ๐ง
altitude:floatโ altitude value in angle.angle:floatโ angle value.anti_aliased:boolโ anti-aliased. yes ma'am, smooth edges.bevel_style:bytesโ bevel style, one ofOuterBevel,InnerBevel,Emboss,PillowEmboss, orStrokeEmboss.bevel_type:bytesโ bevel type, one ofSoftMatte,HardLight,SoftLight.contour:Descriptorโ contour configuration.depth:floatโ depth value in percentage.direction:bytesโ direction, eitherStampInorStampOut.enabled:boolโ whether if the effect is enabled.highlight_color:Descriptorโ highlight color value.highlight_mode:bytesโ highlight blending mode.highlight_opacity:floatโ highlight opacity value in percentage.name:strโ effect name.opacity:floatโ layer effect opacity in percentage.present:boolโ whether if the effect is present in Photoshop UI.shadow_color:Descriptorโ shadow color value.shadow_mode:bytesโ shadow blending mode.shadow_opacity:floatโ shadow opacity value in percentage.shown:boolโ whether if the effect is shown in dialog.size:floatโ size value in pixel.soften:floatโ soften value in pixels.use_global_light:boolโ using global light.use_shape:boolโ using shape.use_texture:boolโ using texture.value:Descriptorโ deprecated
Effect descriptor value. Usedescriptorproperty instead. (thedescriptorproperty is the main character here, fr fr.)
Satin
class psd_tools.api.effects.Satin(descriptor: Descriptor, image_resources: ImageResources)
Satin effect ๐ โ the soft shiny one, and here's every single thing it's got going on:
angle:floatโ angle value in degrees.anti_aliased:boolโ anti-aliased.blend_mode:bytesโ effect blending mode.color:Descriptorโ color.contour:Descriptorโ contour configuration.distance:floatโ distance value in pixels.enabled:boolโ whether if the effect is enabled.inverted:boolโ inverted.name:strโ effect name.opacity:floatโ layer effect opacity in percentage.present:boolโ whether if the effect is present in Photoshop UI.shown:boolโ whether if the effect is shown in dialog.size:floatโ size value in pixel.value:Descriptorโ deprecated
Effect descriptor value. Use descriptor property instead. ๐
psd_tools.api.layers
Layer module. ๐
okay this is the big one โ this module implements the high-level layer API for psd-tools, giving you Pythonic interfaces for working with Photoshop layers. it defines the layer type hierarchy and the common operations. periodt.
Key classes, and yes we're naming every single one:
Layer: base class for all layer types.GroupMixin: mixin for layers that contain children (groups, documents).Group: folder/group layer containing other layers.PixelLayer: regular raster layer with pixel data.TypeLayer: text layer with typography information.ShapeLayer: vector shape layer.SmartObjectLayer: embedded or linked smart object.AdjustmentLayer: non-destructive adjustment (curves, levels, etc.).
Layer hierarchy:
Layers are organized in a tree structure where groups can contain child layers. The GroupMixin provides iteration, indexing, and search capabilities:
# Iterate through all layers
for layer in psd:
print(layer.name)
# Access by index
first_layer = psd[0]
# Check if layer is a specific type
if layer.kind == 'pixel':
pixels = layer.numpy()
Common layer properties:
name: layer name.visible: visibility flag.opacity: opacity (0-255).blend_mode: blend mode enum.bbox: bounding box (left, top, right, bottom).width,height: dimensions.kind: layer type string ('pixel','group','type', etc.).parent: parent layer or document.
Layer operations:
composite(): render layer to PIL Image.numpy(): get pixel data as NumPy array.topil(): convert to PIL Image.has_mask(): check if layer has a mask.has_clip_layers(): check if layer has clipping mask.
Example usage, and this one's a whole vibe, don't skip it:
from psd_tools import PSDImage
psd = PSDImage.open('document.psd')
# Access first layer
layer = psd[0]
# Modify layer properties
layer.visible = False
layer.opacity = 128
layer.name = "New Name"
# Get pixel data
pixels = layer.numpy() # NumPy array
image = layer.topil() # PIL Image
# Work with groups
for group in psd.descendants():
if group.kind == 'group':
print(f"Group: {group.name} with {len(group)} layers")
# Composite specific layer
rendered = layer.composite()
rendered.save('layer.png')
Layer types are automatically determined from the underlying PSD structures and exposed through the kind property for easy type checking. so you literally never have to guess. ๐
Layer
class psd_tools.api.layers.Layer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)
the base class, the blueprint, the moment. โจ
bbox:tuple[int, int, int, int]โ the(left, top, right, bottom)tuple.blend_mode:BlendModeโ blend mode of this layer. Writable, bestie, you can change it. ๐ฅ
Example:
from psd_tools.constants import BlendMode
if layer.blend_mode == BlendMode.NORMAL:
layer.blend_mode = BlendMode.SCREEN
Returns : BlendMode.
bottom:intโ bottom coordinate.
Returns : int.
clip_layers:list[Self]โ the clip layers associated with this layer.
Returns : list of layers.
clipping:boolโ clipping flag for this layer. Writable. ๐has_stroke()โ ReturnsTrueif the shape has a stroke. ๐has_vector_mask()โ ReturnsTrueif the layer has a vector mask.
Returns bool
property height: intโ Height of the layer, bestie.
Returns int
is_group() -> boolโ ReturnTrueif the layer is a group. The way that this one just tells you if it's giving group energy fr fr.
Returns bool
is_visible() -> boolโ Layer visibility. Takes group visibility in account, so it's not just vibing on its own ๐.
Returns bool
property kind: strโ Kind of this layer, such asgroup,pixel,shape,type,smartobject, orpsdimage. Class name without the layer suffix.
Returns str
property layer_id: intโ Layer ID.
Returns int layer id. if the layer is not assigned an id, -1.
property left: intโ Left coordinate. Writable.
Returns int
lock(lock_flags: int = ProtectedFlags.COMPLETE) -> Noneโ Locks a layer accordind to the combination of flags. (yes that typo is in the original, we keep it, it's iconic ๐ )
Parameters
lockflagsโ An integer representing the locking state
Example using the constants of ProtectedFlags and bitwise or operation to lock both pixels and positions:
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)
property mask: Mask | Noneโ Returns mask associated with this layer.
Returns Mask or None
move_down(offset: int = 1) -> Selfโ Moves the layer down a certain offset within the group the layer is in. Sliding down the stack, no cap ๐ฆ.
Parameters
offsetโ The number of positions to move the layer down (can be negative).
Raises
ValueErrorโ If layer has no parent or parent is not a groupIndexErrorโ If the new index is out of bounds
Returns self
move_to_group(group: GroupMixin) -> Selfโ Deprecated: Usegroup.append(layer)instead.
Parameters
groupโ The group the current layer will be moved into.
move_up(offset: int = 1) -> Selfโ Moves the layer up a certain offset within the group the layer is in. Going up, main character energy โจ.
Parameters
offsetโ The number of positions to move the layer up (can be negative).
Raises
ValueErrorโ If layer has no parent or parent is not a groupIndexErrorโ If the new index is out of bounds
Returns self
property name: strโ Layer name. Writable.
Returns str
next_sibling(visible: bool = False) -> Self | Noneโ Next sibling of this layer. Finding the layer's next bestie in the layer tree ๐ซถ.numpy(channel: str | None = None, real_mask: bool = True) -> ndarray | Noneโ Get NumPyarrayof the layer.
Parameters
channelโ Which channel to return, can be'color','shape','alpha', or'mask'. Default is'color+alpha'.
Returns numpy.ndarray or None if there is no pixel.
property offset: tuple[int, int]โ(left, top)tuple. Writable.
Returns tuple
property opacity: intโ Opacity of this layer in[0, 255]range. Writable.
Returns int
property origination: list[Origination]โ Property for a list of live shapes or a line.
Some of the vector masks have associated live shape properties, that are Photoshop feature to handle primitive shapes such as a rectangle, an ellipse, or a line. Vector masks without live shape properties are plain path objects.
See psd_tools.api.shape.
Returns List of Invalidated, Rectangle, RoundedRectangle, Ellipse, or Line.
property parent: GroupMixinProtocol | Noneโ Parent of this layer. Every queen knows her roots ๐.previous_sibling(visible: bool = False) -> Self | Noneโ Previous sibling of this layer. The layer right before this one in the lineup ๐ธ.property reference_point: tuple[float, float]โ Reference point of this layer as(x, y)tuple in the canvas coordinates. Writable.
Reference point is used for transformations such as rotation and scaling.
Returns (x, y) tuple
remove_mask() -> Noneโ Remove the pixel mask from this layer.
Raises ValueError โ If the layer does not have a mask.
property right: intโ Right coordinate.
Returns int
property sheet_color: SheetColorTypeโ Color label of this layer in the Photoshop layers panel. Writable.
Returns SheetColorType
property size: tuple[int, int]โ(width, height)tuple.
Returns tuple
property stroke: Stroke | Noneโ Property for strokes.property tagged_blocks: TaggedBlocksโ Layer tagged blocks that is a dict-like container of settings.
๐ pro tip bestie: peek over at psd_tools.constants.Tag for every key that's up for grabs.
Returns โ TaggedBlocks.
Example:
from psd_tools.constants import Tag
metadata = layer.tagged_blocks.get_data(Tag.METADATA_SETTING)
property top: int
The top coordinate, duh ๐ . You can write to it โ so lowkey you can move the whole layer up and down to your heart's content.
Returns โ int.
topil(channel: int | None = None, apply_icc: bool = True) -> Image | None
Gives you the PIL Image of the layer. Yes, actual pixels you can touch. Iconic.
Parameters
- channel โ which channel you want back. Like,
0gets you the'R'channel in an RGB image. Check the menu atpsd_tools.constants.ChannelID. When it'sNone, the method hands you all the channels that the PIL modes can handle. All of 'em. Periodt. - apply_icc โ whether to apply ICC profile conversion to sRGB.
Returns โ PIL.Image.Image, or None if the layer has, like, zero pixels. ๐
Example:
from psd_tools.constants import ChannelID
image = layer.topil()
red = layer.topil(ChannelID.CHANNEL_0)
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)
Note: not every PSD image mode is supported byPIL.Image.Imagefr fr. For example,'CMYK'mode can't include an alpha channel in PIL. When that happens,topiljust drops the alpha channel. Not dramatic, just reality. ๐ซถ
update_mask(image: Image, top: int | None = None, left: int | None = None, compression: Compression = Compression.RLE) -> Mask
Swap in a brand new pixel mask for this layer. Glow-up time โจ.
If your image has an alpha channel (think RGBA, LA), that alpha channel becomes the mask data. If not, the image gets converted to grayscale (L mode). And the rules? White (255) means fully unmasked, black (0) means fully masked. That's the vibe.
Parameters
- image โ the new source Image for the mask.
- top โ new top offset of the mask. Defaults to whatever the current mask top is.
- left โ new left offset of the mask. Defaults to the current mask left.
- compression โ the compression algorithm used for the mask data.
Returns โ the updated Mask.
Raises ValueError โ if the layer doesn't even have a mask. Rude, but fair.
property vector_mask: VectorMask | None
Hands you the vector mask that's linked up with this layer.
Returns โ a VectorMask, or None if there isn't one. ๐ฆ
property visible: bool
Layer visibility, simple as. Heads up though: it does not account for group visibility. Writable, so toggle away.
Returns โ bool.
property width: int
How wide the layer is.
Returns โ int.
๐ Artboard ๐
class psd_tools.api.layers.Artboard(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)
An Artboard is a โจspecialโจ kind of group โ one that rocks a pre-defined viewbox. Main character energy, honestly.
property bbox: tuple[int, int, int, int]
A (left, top, right, bottom) tuple.
property bottom: int
The bottom coordinate. It's computed from the children, so it's read-only โ look, don't touch. ๐
composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray | None = None, alpha: float | ndarray | None = None, layer_filter: Callable | None = None, apply_icc: bool = True) -> Image | None
Composites the layer, and it automatically applies the artboard's background color. So convenient bestie.
When either color or alpha isn't explicitly handed over, it reads the artboard background from the ARTBOARD_DATA tagged block (artboardBackgroundType and Clr descriptor) and uses the missing value โ or values โ as the compositing backdrop. It's giving resourceful. ๐
property left: int
The left coordinate (computed from children, read-only).
property right: int
The right coordinate (computed from children, read-only).
property top: int
The top coordinate (computed from children, read-only).
๐ Group ๐
class psd_tools.api.layers.Group(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)
A group of layers. Like a little friend group but for pixels. ๐ซถ
Example:
group = psd[1]
for layer in group:
if layer.kind == 'pixel':
print(layer.name)
property blend_mode: BlendMode
The blend mode of this layer. Writable. Go off. ๐ธ
property bottom: int
The bottom coordinate (computed from children, read-only).
property clipping: bool
Clipping flag for this layer. Writable.
Returns โ bool.
composite(viewport: tuple[int, int, int, int] | None = None, force: bool = False, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, layer_filter: Callable | None = None, apply_icc: bool = True) -> Image | None
Composites the layer and the masks (mask, vector mask, and clipping layers). The whole package. ๐
Parameters
- viewport โ the viewport bounding box, given as an
(x1, y1, x2, y2)tuple. Default is the layer'sbbox. - force โ boolean flag to force vector drawing.
- color โ backdrop color, given as a scalar or a tuple of scalars. The value should live in
[0.0, 1.0]. Like,(1., 0., 0.)gives you red in RGB color mode. โค๏ธ - alpha โ backdrop alpha in
[0.0, 1.0]. - layer_filter โ a Callable that takes a layer as an argument and returns whether or not that layer gets composited. Default is
is_visible().
Returns โ PIL.Image.Image.
static extract_bbox(layers: Sequence[Layer] | GroupMixin, include_invisible: bool = False, include_clipping: bool = False) -> tuple[int, int, int, int]
Returns a bounding box for the layers โ or (0, 0, 0, 0) if the layers have no bounding box at all. ๐
Parameters
- layers โ a sequence of layers, or a group.
- include_invisible โ include invisible layers in the calculation.
- include_clipping โ include clipping layers in the calculation. Defaults to
Falseso it matches visible pixel bounds.
Returns โ a tuple of four int.
classmethod group_layers(parent: GroupMixin, layers: Sequence[Layer], name: str = 'Group', open_folder: bool = True) -> Self
โ ๏ธ Deprecated: use psdimage.create_group(layer_list, name) instead. Old news, bestie.
Parameters
- parent โ the parent group where the shiny newly created
Groupobject gets added. - layers โ the layers to group. Can be any subclass of
Layer. - name โ the display name of the group. Defaults to
"Group". - open_folder โ boolean that decides whether the folder is open or closed in photoshop. Defaults to
True.
Returns โ a Group.
Raises ValueError โ if layers is empty. Can't group nothing, babe. ๐
is_group() -> bool
Returns True if the layer is a group.
Returns โ bool.
property left: int
The left coordinate (computed from children, read-only).
classmethod new(parent: GroupMixin, name: str = 'Group', open_folder: bool = True) -> Self
Makes a brand new Group object with minimal records and data channels and metadata, so the group slots into the PSD file all proper-like. โจ
Parameters
- name โ the display name of the group. Defaults to
"Group". - open_folder โ boolean that decides whether the folder is open or closed in photoshop. Defaults to
True. - parent โ optional parent folder to move the freshly created group into.
Returns โ a Group object.
Raises ValueError โ if parent is None.
property open_folder: bool
Returns True if the group is an open folder.
Returns โ bool.
property right: int
The right coordinate (computed from children, read-only).
property top: int
The top coordinate (computed from children, read-only).
๐ PixelLayer ๐
class psd_tools.api.layers.PixelLayer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)
A layer that has rasterized image in pixels. The classic. The blueprint. ๐
Example:
assert layer.kind == 'pixel':
image = layer.composite()
image.save('layer.png')
classmethod frompil(image: Image, parent: GroupMixin, name: str = 'Layer', top: int = 0, left: int = 0, compression: Compression = Compression.RLE, **kwargs: Any) -> PixelLayerโ bestie this is the glow-up move: spin up a wholePixelLayerfrom a PIL image so it can live inside a given psd file ๐ซถ
Params, one by one:
- image โ the
Imageobject you're converting into photoshop, no take-backs. - parent โ the parent group or
PSDImagethis layer belongs to. - name โ what you're calling the layer. Defaults to
"Layer"when you can't be bothered (we've all been there). - top โ pixelwise offset from the top of the canvas for the new layer.
- left โ pixelwise offset from the left of the canvas for the new layer.
- compression โ the compression algorithm to use for the data.
Returns: a PixelLayer object ๐
Raises:
TypeErrorโ if image is not a PIL Image ๐ValueErrorโ if parent isNone๐ญ
Note: If the image has an alpha channel and the parent PSD mode supports layer transparency (e.g.RGBA,LA), the alpha is stored as the layer transparency channel and no extra mask is created. For PSD modes that do not carry a transparency band (e.g.RGB,CMYK), the alpha channel is instead stored as a pixel mask (USER_LAYER_MASK). iykyk โจ
๐ ShapeLayer ๐
class psd_tools.api.layers.ShapeLayer(*args: Any)
A layer that has drawing in a vector mask. Shape girlies stay winning โจ
property bbox: tuple[int, int, int, int]โ(left, top, right, bottom)tuple.property bottom: intโ bottom coordinate.
Returns: int
property left: intโ left coordinate. Writable. ๐property right: intโ right coordinate.
Returns: int
property top: intโ top coordinate. Writable. ๐
Returns: int
๐ SmartObjectLayer ๐
class psd_tools.api.layers.SmartObjectLayer(parent: GroupMixin, record: LayerRecord, channels: ChannelDataList)
A layer that inserts external data ๐ธ Use the smart_object attribute to get at that external data โ peep SmartObject.
Example, because a demo clears the vibe check:
import io
so = layer.smart_object
if so.detected_filetype == 'jpg':
# Use open(external_dir=...) when processing untrusted PSD files.
with so.open() as f:
image = Image.open(io.BytesIO(f.read()))
property smart_object: SmartObjectโ the associated smart object.
Returns: SmartObject.
๐ฆ TypeLayer ๐ฆ
class psd_tools.api.layers.TypeLayer(*args: Any)
A layer that has text and styling information for fonts or paragraphs ๐
Text lives at the text property. Styling info for paragraphs is in engine_dict. Document styling info like the font list is in resource_dict. And rn? Textual information is read-only, so look, don't touch, bestie.
Example, and honestly it ate:
if layer.kind == 'type':
print(layer.text)
print(layer.engine_dict['StyleRun'])
# Extract font for each substring in the text.
text = layer.engine_dict['Editor']['Text'].value
fontset = layer.resource_dict['FontSet']
runlength = layer.engine_dict['StyleRun']['RunLengthArray']
rundata = layer.engine_dict['StyleRun']['RunArray']
index = 0
for length, style in zip(runlength, rundata):
substring = text[index:index + length]
stylesheet = style['StyleSheet']['StyleSheetData']
font = fontset[stylesheet['Font']]
print('%r gets %s' % (substring, font))
index += length
property document_resources: Dictโ resource set relevant to the document.property engine_dict: Dictโ the styling information dict.property font_names: list[str]โ list of PostScript font names used in this text layer.
Convenience shortcut for:
[font.postscript_name for font in layer.typesetting.fonts]
property resource_dict: Dictโ resource set.property text: strโ text in the layer. Read-only.
Note: New-line character in Photoshop is '\r'. Not `'\n'. Yes really. Photoshop said "be different" ๐
property text_type: TextType | Noneโ text type. Read-only.
Returns:
psd_tools.constants.TextType.POINTfor point type text (also known as character type)psd_tools.constants.TextType.PARAGRAPHfor paragraph type text (also known as area type)Noneif text type cannot be determined or information is unavailable
See psd_tools.constants.TextType.
property transform: tuple[float, float, float, float, float, float]โ matrix(xx, xy, yx, yy, tx, ty)applies affine transformation โจproperty typesetting: TypeSettingโ structured typographic data.
Returns a TypeSetting object that provides Pythonic access to fonts, paragraphs, styled runs, and default styles โ no navigating raw engine data dicts required, we love a wrapper ๐
Example:
ts = layer.typesetting
for paragraph in ts:
print(paragraph.style.justification)
for run in paragraph.runs:
print(run.text, run.style.font_name, run.style.font_size)
See also: engine_dict, resource_dict for raw data.
property warp: DescriptorBlock | Noneโ warp configuration.
๐ psd_tools.api.mask ๐
The Mask module, periodt.
Masks decide the visible area of a layer ๐ There are two types of masks: user mask and vector mask. User mask = any pixel-based mask. Vector mask = a mask from a shape path. Two icons, one purpose.
Masks are accessible from the layer's mask property:
from psd_tools import PSDImage
psdimage = PSDImage.open('example.psd')
layer = psdimage[0]
mask = layer.mask
assert mask is not None
print(mask.bbox) # (left, top, right, bottom)
mask_image = mask.topil() # Show the mask as a PIL Image.
if mask_image is not None:
mask_image.save("mask.png")
To create a new mask, use the layer's create_mask() method:
from psd_tools import PSDImage
from PIL import Image
psdimage = PSDImage.new(mode="RGB", size=(128, 128))
layer = psdimage.create_pixel_layer(Image.new("RGB", (128, 128)))
layer.create_mask(Image.new("L", (128, 128), 255))
And note that creating a pixel layer from an RGBA image will automatically create a user mask โ it's giving "did it myself, you're welcome" ๐
psdimage = PSDImage.new(mode="RGB", size=(128, 128))
layer = psdimage.create_pixel_layer(Image.new("RGBA", (128, 128)))
๐ Mask ๐
class psd_tools.api.mask.Mask(layer: LayerProtocol)
Mask data attached to a layer ๐
There are two distinct internal mask data: user mask and vector mask. User mask refers to any pixel-based mask, whereas vector mask refers to a mask from a shape path. Internally, the two masks are combined and referred to as the real mask. Two sources, one final boss.
property background_color: intโ background color.property bbox: tuple[int, int, int, int]โ BBox.property bottom: intโ bottom coordinate.property data: MaskDataโ return raw mask data, orNoneif no data.property disabled: boolโ disabled.property flags: MaskFlagsโ flags.has_real() -> boolโ returnTrueif the mask has real flags.property height: intโ height.property left: intโ left coordinate.property parameters: Anyโ parameters.property real_flags: MaskFlags | Noneโ real flag.property right: intโ right coordinate.property size: tuple[int, int]โ(Width, Height)tuple.property top: intโ top coordinate.topil(real: bool = True, layer_sized: bool = False, **kwargs: Any) -> Image | Noneโ get a PIL Image of the mask ๐ผ๏ธ
Params:
- real โ when
True, returns pixel + vector mask combined. - layer_sized โ when
True, returns a layer-sized image pre-filled withbackground_color, with the mask data pasted at the correct position. WhenFalse(the default), returns the raw stored mask data at mask dimensions.
Returns: PIL Image object, or None if the mask is empty.
property width: intโ width.
๐ซ psd_tools.api.shape ๐ซ
Shape module.
okay so in PSD/PSB land every single shape is a VectorMask hanging out inside its layer, and optionally there might be an Origination object running the live-shape situation plus a Stroke telling the outline how to be cute. that's the whole vibe. ๐
โจ VectorMask โจ
class psd_tools.api.shape.VectorMask(data: VectorMaskSetting)
Vector mask data, bestie.
A vector mask is a resolution-independent mask made of one or more Path objects. In Photoshop, all the path objects are Bezier curves, no cap. Peep the paths property to see how to deal with path objects. ๐
bbox:tuple[float, float, float, float]โ bounding box tuple(left, top, right, bottom)in relative coordinates, where the top-left corner is(0., 0.)and the bottom-right corner is(1., 1.).
This bbox accounts for the full extent of all cubic Bezier curves, not just the anchor points. so like, the whole squishy curve, not just the dots.
Returns: tuple
clipboard_record:ClipboardRecord | Noneโ clipboard record carrying bounding box info.
Depending on which Photoshop version you're in, this field can be None. ๐
disabled:boolโ if the mask is disabled.initial_fill_rule:intโ initial fill rule.
When 0, fill inside of the path. When 1, fill outside of the shape.
Returns: int
inverted:boolโ invert the mask.not_linked:boolโ if the knots are not linked.paths:list[Subpath]โ list ofSubpath. ASubpathis a list-like structure holding one or moreKnotitems. AKnotcontains the relative coordinates of control points for a Bezier curve.indextells you which origination item the subpath belongs to, andoperationtells you how to combine multiple shape paths.
In PSD, the path fill rule is even-odd.
Example:
for subpath in layer.vector_mask.paths:
anchors = [(
int(knot.anchor[1] * psd.width),
int(knot.anchor[0] * psd.height),
) for knot in subpath]
Returns: List of Subpath.
๐ Stroke ๐
class psd_tools.api.shape.Stroke(data: VectorStrokeContentSetting)
Stroke holds the decorative info for strokes โ the lil fashion details, basically. ๐
This is a thin wrapper around the Descriptor structure. Check the _data attribute to get the raw data.
blend_mode:Anyโ blend mode.content:Anyโ fill effect.enabled:boolโ if the stroke is enabled.fill_enabled:boolโ if the stroke fill is enabled.line_alignment:strโ alignment, one ofinner,outer,center.line_cap_type:strโ cap type, one ofbutt,round,square.line_dash_offset:floatโ line dash offset in float.
Returns: float
line_dash_set:listโ line dash set in list ofUnitFloat.
Returns: list
line_join_type:strโ join type, one ofmiter,round,bevel.line_width:floatโ stroke width in float.miter_limit:Anyโ miter limit in float.opacity:Anyโ opacity value.stroke_adjust:Anyโ stroke adjust.
๐ฆ Origination ๐ฆ
Origination keeps the live shape properties for some of the primitive shapes. You get to these objects through the origination property of layers. These are the primitive shapes that are defined: Invalidated, Line, Rectangle, Ellipse, and RoundedRectangle. slay, a whole little family. ๐ธ
๐ Invalidated ๐
class psd_tools.api.shape.Invalidated(data: Descriptor)
Invalidated live shape.
This equals a primitive shape that does not provide Live shape properties. So use VectorMask to access shape information instead of this origination object, bestie โ that's where the tea actually is.
invalidated:boolโbool.
Type: return
๐ Line ๐
class psd_tools.api.shape.Line(data: Descriptor)
Line live shape.
arrow_conc:intโint.
Type: return
arrow_end:boolโ line arrow end.
Returns: bool
arrow_length:floatโ line arrow length.
Returns: float
arrow_start:boolโ line arrow start.
Returns: bool
arrow_width:floatโ line arrow width.
Returns: float
bbox:tuple[float, float, float, float]โ bounding box of the live shape.
Returns: Descriptor
index:intโ origination item index.
Returns: int
invalidated:boolโbool.
Type: return
line_end:Descriptorโ line end.
Returns: Descriptor
line_start:Descriptorโ line start.
Returns: Descriptor
line_weight:floatโ line weight.
Returns: float
origin_type:intโ type of the vector shape.1: Rectangle2: RoundedRectangle4: Line5: Ellipse
Returns: int
resolution:floatโ resolution.
Returns: float
โญ Ellipse โญ
class psd_tools.api.shape.Ellipse(data: Descriptor)
Ellipse live shape.
bbox:tuple[float, float, float, float]โ bounding box of the live shape.
Returns: Descriptor
index:intโ origination item index.
Returns: int
invalidated:boolโbool.
Type: return
origin_type:intโ type of the vector shape.1: Rectangle2: RoundedRectangle4: Line5: Ellipse
Returns: int
resolution:floatโ resolution.
Returns: float
๐ Rectangle ๐
class psd_tools.api.shape.Rectangle(data: Descriptor)
Rectangle live shape.
bbox:tuple[float, float, float, float]โ bounding box of the live shape.
Returns: Descriptor
index:intโ origination item index.
Returns: int
invalidated:boolโbool.
Type: return
origin_type:intโ type of the vector shape.1: Rectangle2: RoundedRectangle4: Line5: Ellipse
Returns: int
resolution:floatโ resolution.
Returns: float
๐ RoundedRectangle ๐
class psd_tools.api.shape.RoundedRectangle(data: Descriptor)
Rounded rectangle live shape. the softest corners in the game, periodt.
bbox:tuple[float, float, float, float]โ bounding box of the live shape.
Returns: Descriptor
index:intโ origination item index.
Returns: int
invalidated:boolโbool.
Type: return
origin_type:intโ type of the vector shape.1: Rectangle2: RoundedRectangle4: Line5: Ellipse
Returns: int
radii:Anyโ corner radii of rounded rectangles. The order istop-left,top-right,bottom-left,bottom-right.
Returns: Descriptor
resolution:floatโ resolution.
Returns: float
๐ psd_tools.api.smart_object ๐
Smart object module. iykyk.
๐ซถ SmartObject ๐ซถ
class psd_tools.api.smart_object.SmartObject(layer: LayerProtocol)
A smart object that represents an embedded or external file.
Smart objects are attached to SmartObjectLayer. ๐
data:bytesโ embedded file content as bytes.
So, kind == 'data'? This hands you back the bytes sitting right there in the PSD โ literally zero filesystem access, nothing touched on disk, we love a no-side-effects moment ๐
. But kind == 'external'? It calls open() with no external_dir argument, which means it trusts fullPath from the PSD verbatim โ like, fully, no questions asked ๐ญ. If you're dealing with files you don't trust, please please please prefer open() with an explicit external_dir. That's the whole vibe check right there.
property detected_filetype: str | Noneโ a best-effort guess at the file type, which only kicks in as a fallback whenfiletypeisNone.
Here's the resolution order, bestie, step by step:
filetypeโ whatever value is actually stored in the PSD. The real one.- The extension grabbed from
filename(lower-cased, dot stripped). - Magic-byte sniffing of the first few embedded bytes โ only for
kind == 'data', because external objects are not read from disk, which keeps this property side-effect-free. Queen behaviour honestly.
Warning: steps 2 and 3 are pure heuristics. Do not use the result for security-sensitive decisions โ like deciding whether to execute content, or whether to trust a type boundary. That's a no from me ๐.
property filename: strโ the original file name of the object. That's it, that's the whole thing.property filesize: intโ file size of the object.property filetype: str | Noneโ the 4-byte file-type code stored in the PSD, lowercased and stripped. ReturnsNonewhen the field is absent or blank (some Adobe Illustrator smart objects literally store four spaces instead of a real type code โ four spaces, iconic of them ๐ญ). If you want a guess that falls back to filename extension and magic bytes, usedetected_filetype.is_psd() -> boolโ returnsTrueif the file is embedded PSD/PSB. It checks the storedfiletypefirst; and if that'sNone(blank field, again) it falls back to inspecting the first four magic bytes of the embedded data. The filename extension is intentionally not used as a fallback โ so it never misclassifies non-PSD files that are just named*.psd. Fraud detection, slay ๐ฅ.property kind: strโ the kind of the link:'data','alias', or'external'.open(external_dir: str | PathLike | None = None) -> Iterator[IO[bytes]]โ opens the smart object as binary IO.
Parameters
- external_dir โ the directory to resolve external paths against. When provided, a
fullPaththat resolves outside this directory is silently ignored andrelPathis tried instead. ArelPaththat resolves outside this directory raisesValueError. Strongly recommended when you're processing untrusted PSD files. Like, strongly.
Example:
with layer.smart_object.open() as f:
data = f.read()
property resolution: floatโ resolution of the object.save(filename: str | PathLike | None = None, directory: str | PathLike | None = None, external_dir: str | PathLike | None = None) -> Noneโ saves the smart object to a file.
Parameters
- filename โ explicit destination path. When provided it's used as-is and
directoryis ignored. (Sorry girl,directorydoesn't get a say here.) - directory โ output directory used when
filenameisNone. Defaults to the current working directory. The embedded basename gets written inside this directory, and any path-traversal sequences in the embedded name are stripped automatically. Safety first always โจ. - external_dir โ passed straight through to
open()when the smart object kind is'external'. It constrains which paths on disk may be read. Strongly recommended when processing untrusted PSD files.
Raises ValueError โ if the embedded name contains no safe basename, resolves outside directory, or (for external kind) the source path escapes external_dir.
property transform_box: tuple[float, float, float, float, float, float, float, float] | Noneโ a tuple with the coordinates of the smart object's transformed box. This box is the result of one or more transformations โ scaling, rotation, translation, skewing โ applied to the original bounding box of the smart object. Math ate ๐ซถ.
The format of the tuple is: (x1, y1, x2, y2, x3, y3, x4, y4)
Where 1 is the top left corner, 2 is top right, 3 is bottom right, and 4 is bottom left. Memorise that, bestie, it'll save you.
property unique_id: strโ UUID of the object.property warp: object | Noneโ warp parameters.
๐ psd_tools.composite ๐
Composite module for layer rendering and blending.
This subpackage is the whole rendering engine โ it composites PSD layers into raster images, implements Photoshop's blend modes, layer effects, and vector shape rasterization. Main character module, honestly ๐.
Note: this module needs optional dependencies. Install with:
pip install 'psd-tools[composite]'
Or using uv:
uv sync --extra composite
The composite extra includes:
aggdraw: for vector path and bezier curve rasterizationscipy: for advanced image processing operationsscikit-image: for morphological operations in effects
Key modules:
psd_tools.composite.composite: main compositing functionspsd_tools.composite.blend: blend mode implementationspsd_tools.composite.effects: layer effects (stroke, shadow, etc.)psd_tools.composite.vector: vector shape and path renderingpsd_tools.composite.paint: fill rendering (gradients, patterns)
Example usage:
from psd_tools import PSDImage
psd = PSDImage.open('document.psd')
# Composite entire document to PIL Image
image = psd.composite()
image.save('output.png')
# Composite specific layer
layer_image = psd[0].composite()
The compositing engine uses NumPy arrays for efficient pixel manipulation, and it supports all of Photoshop's standard blend modes including multiply, screen, overlay, soft light, and more. Obsessed ๐.
Performance considerations:
- Compositing can be memory-intensive for large documents
- Vector shapes require
aggdrawfor accurate rendering - Some effects have limited support compared to Photoshop
This module provides layer rendering and compositing functionality.
Installation: requires optional dependencies:
pip install psd-tools[composite]
Or with uv:
uv sync --extra composite
๐ Composite Functions ๐
psd_tools.composite.composite(group: Layer | PSDImage, color: float | tuple[float, ...] | ndarray = 1.0, alpha: float | ndarray = 0.0, viewport: tuple[int, int, int, int] | None = None, layer_filter: Callable[[Layer], bool] | None = None, force: bool = False, as_layer: bool = False) -> tuple[ndarray, ndarray, ndarray]
Composite layers and return NumPy arrays.
This function composites the given layer or document into NumPy arrays representing color, shape, and alpha channels. It applies layer blending, effects, masks, and clipping according to the PSD specification. The way it just... does all of that ๐ญโจ.
Parameters
- group โ
LayerorPSDImageto composite - color โ initial backdrop color (0.0-1.0, default:
1.0). Can be a scalar float applied to all channels, a tuple of per-channel values, or anndarray. - alpha โ initial backdrop alpha (0.0-1.0, default:
0.0). Can be scalar orndarray. - viewport โ bounding box
(left, top, right, bottom)to composite. IfNone, uses layer bounds - layer_filter โ optional
callable(layer) -> boolto filter which layers to composite - force โ if
True, force re-rendering of all layers including vector shapes and fills - as_layer โ if
True, treat the group as a layer (apply blend mode to backdrop)
Returns
color: RGB/CMYK/Grayscale values in range [0.0, 1.0]shape: layer shape/coverage mask in range [0.0, 1.0]alpha: composite alpha channel in range [0.0, 1.0]
Return type
Tuple of (color, shape, alpha) as float32 ndarrays with shape (height, width, channels).
Examples
>>> from psd_tools import PSDImage
>>> psd = PSDImage.open('example.psd')
>>> color, shape, alpha = composite(psd)
>>> # Apply custom backdrop
>>> color, shape, alpha = composite(psd, color=(1.0, 0.0, 0.0), alpha=1.0)
>>> # Force re-render vector layers
>>> color, shape, alpha = composite(psd, force=True)
>>> # Composite only visible layers
>>> color, shape, alpha = composite(psd, layer_filter=lambda l: l.visible)
Note: - Requires optional composite dependencies (aggdraw,scipy,scikit-image) for vector shape rendering, gradient fills, and layer effects. - Adjustment layers have limited support. - Text rendering is not supported (text layers show as raster if available).
psd_tools.composite.composite_pil(layer: Layer | PSDImage, color: float | tuple[float, ...] | ndarray, alpha: float | ndarray, viewport: tuple[int, int, int, int] | None, layer_filter: Callable[[Layer], bool] | None, force: bool, as_layer: bool = False, apply_icc: bool = True) -> Image | None
Composite layers and return a PIL Image.
This function composites the given layer or document into a PIL Image, applying blend modes, effects, and color management. PIL girlies, this one's for you ๐ซถ.
Parameters
- layer โ
LayerorPSDImageto composite colorโ Initial backdrop color,0.0-1.0. Can be scalar, tuple, or ndarray ๐alphaโ Initial backdrop alpha,0.0-1.0. Can be scalar or ndarray โจviewportโ Bounding box(left, top, right, bottom)to composite. IfNone, uses layer bounds ๐layer_filterโ Optional callable to filter which layers to composite. Should returnTrueto include ๐ฆforceโ IfTrue, force re-rendering of all layers (ignore cached pixels) ๐ฅas_layerโ IfTrue, apply layer blend modes (default:Falsefor document-level compositing) ๐apply_iccโ IfTrue, apply ICC profile color correction (default:True) ๐
Returns ๐
PIL Image with composited result, or None if viewport is empty.
Note: ๐ซถ
- Requires optional composite dependencies (
aggdraw,scipy,scikit-image) ๐ - LAB and Duotone color modes have limited blending support ๐
- Alpha channel handling varies by color mode ๐ธ
๐ Blend Modes ๐
Blend mode implementations.
This module implements Photoshop's blend modes for compositing layers. Blend modes determine how a layer's colors interact with the layers beneath it. Each function implements the mathematical formula for a specific blend mode.
The blend functions operate on NumPy arrays with normalized float32 values (0.0-1.0) representing pixel color channels. They follow Adobe's PDF Blend Mode specification.
Blend mode categories:
- Normal modes:
normal: Source replaces backdrop (no blending)
- Darken modes:
darken: Selects darker of source and backdropmultiply: Multiplies colors (darkens)color_burn: Darkens backdrop to reflect sourcelinear_burn: Similar to multiply but more extremedarker_color: Selects darker color (non-separable)
- Lighten modes:
lighten: Selects lighter of source and backdropscreen: Inverted multiply (lightens)color_dodge: Brightens backdrop to reflect sourcelinear_dodge: Same as addition (Add blend mode)lighter_color: Selects lighter color (non-separable)
- Contrast modes:
overlay: Combination of multiply and screensoft_light: Soft version of overlayhard_light: Hard version of overlayvivid_light: Combination of color dodge and burnlinear_light: Combination of linear dodge and burnpin_light: Replaces colors based on brightnesshard_mix: Posterizes to primary colors
- Inversion modes:
difference: Absolute difference between colorsexclusion: Similar to difference but lower contrast
- Component modes (non-separable):
hue: Preserves luminosity and saturation, replaces huesaturation: Preserves luminosity and hue, replaces saturationcolor: Preserves luminosity, replaces hue and saturationluminosity: Preserves hue and saturation, replaces luminosity
Implementation details:
- Separable blend modes process each color channel independently
- Non-separable modes convert to HSL color space first
- All functions expect normalized
float32arrays (0.0-1.0range) - Division by zero is protected with small epsilon values
Example usage:
import numpy as np
from psd_tools.composite.blend import multiply, screen
# Create backdrop and source colors (normalized)
backdrop = np.array([0.5, 0.3, 0.8], dtype=np.float32)
source = np.array([0.7, 0.6, 0.2], dtype=np.float32)
# Apply blend mode
result = multiply(backdrop, source)
# Result: [0.35, 0.18, 0.16]
The BLEND_FUNC dictionary maps BlendMode <#psd_tools.constants.BlendMode> enums to their corresponding functions for easy lookup during compositing.
psd_tools.composite.blend.divide(Cb: ndarray, Cs: ndarray) -> ndarray
Looks at the color information in each channel and divides the blend color from the base color.
psd_tools.composite.blend.hard_mix(Cb: ndarray, Cs: ndarray) -> ndarray
Adds the red, green and blue channel values of the blend color to the RGB values of the base color. If the resulting sum for a channel is 255 or greater, it receives a value of 255; if less than 255, a value of 0. Therefore, all blended pixels have red, green, and blue channel values of either 0 or 255. This changes all pixels to primary additive colors (red, green, or blue), white, or black.
psd_tools.composite.blend.hsl2hsv(img: ndarray) -> ndarray
Convert an HSL image to HSV space using vectorized arrays.
psd_tools.composite.blend.hsl2rgb(img: ndarray) -> ndarray
Convert an HSL image to RGB space using vectorized arrays.
psd_tools.composite.blend.hsv2hsl(img: ndarray) -> ndarray
Convert an HSV image to HSL space using vectorized arrays.
psd_tools.composite.blend.linear_light(Cb: ndarray, Cs: ndarray) -> ndarray
Burns or dodges the colors by decreasing or increasing the brightness, depending on the blend color. If the blend color (light source) is lighter than 50% gray, the image is lightened by increasing the brightness. If the blend color is darker than 50% gray, the image is darkened by decreasing the brightness.
psd_tools.composite.blend.non_separable(k: str = 's')
Wrap non-separable blending function for CMYK handling.
psd_tools.composite.blend.pin_light(Cb: ndarray, Cs: ndarray) -> ndarray
Replaces the colors, depending on the blend color. If the blend color (light source) is lighter than 50% gray, pixels darker than the blend color are replaced, and pixels lighter than the blend color do not change. If the blend color is darker than 50% gray, pixels lighter than the blend color are replaced, and pixels darker than the blend color do not change. This is useful for adding special effects to an image.
psd_tools.composite.blend.rgb2hsl(img: ndarray) -> ndarray
Convert an RGB image to HSL space using vectorized arrays.
psd_tools.composite.blend.vivid_light(Cb: ndarray, Cs: ndarray) -> ndarray
Burns or dodges the colors by increasing or decreasing the contrast, depending on the blend color. If the blend color (light source) is lighter than 50% gray, the image is lightened by decreasing the contrast. If the blend color is darker than 50% gray, the image is darkened by increasing the contrast.
The blend module implements Photoshop's blend modes following the Adobe PDF specification. All blend functions operate on normalized float32 NumPy arrays.
๐ฆ Vector Rendering ๐ฆ
Vector shapes and path operations for compositing.
psd_tools.composite.vector.draw_stroke(layer: Layer <#psd_tools.api.layers.Layer>) -> ndarray
Draw a stroke.
Requires aggdraw for bezier curve rasterization.
psd_tools.composite.vector.draw_vector_mask(layer: Layer <#psd_tools.api.layers.Layer>) -> ndarray
Draw a vector mask.
Requires aggdraw for bezier curve rasterization.
Vector shape and path rendering using aggdraw for bezier curve rasterization.
๐ Effects Rendering ๐
Layer effects rendering.
This module implements rendering for Photoshop layer effects (also known as layer styles). Effects are non-destructive visual enhancements applied to layers such as strokes, shadows, glows, and overlays.
Note: Effects rendering requires scikit-image. Install with:
pip install 'psd-tools[composite]'
Currently supported effects:
- Stroke: Outline around layer shape or pixels
- Supports solid color, gradient, and pattern fills
- Position: inside, outside, or centered
- Limited compared to Photoshop's full implementation
Partially supported or limited effects:
- Drop shadow, inner shadow, outer glow, inner glow
- These may render but with reduced accuracy
The main function draw_stroke_effect() handles stroke rendering by:
- Extracting the layer's alpha channel or shape mask
- Applying morphological operations (dilation/erosion) based on stroke size and position
- Filling the stroke region with the specified paint (solid color, gradient, pattern)
- Returning the rendered stroke as a NumPy array
Implementation notes:
- Effects are image-based rather than vector-based, which may differ from Photoshop
- For layers with vector paths, ideally strokes should be drawn geometrically
- Some effect parameters may not be fully supported
- Complex effect combinations may not render identically to Photoshop
Example usage (internal):
from psd_tools.composite.effects import draw_stroke_effect
# Called during layer compositing
viewport = (0, 0, 100, 100) # Region to render
shape = layer_alpha_channel # NumPy array
desc = stroke_descriptor # Effect parameters
color, alpha = draw_stroke_effect(viewport, shape, desc, psd)
The effects system integrates with the main compositing pipeline and is automatically applied when rendering layers that have effects enabled.
Layer effects rendering including strokes, shadows, and glows. Requires scikit-image for morphological operations.
๐ psd_tools.compression ๐
Image compression utilities for PSD channel data.
This subpackage provides compression and decompression codecs for raw pixel data in PSD files. Adobe Photoshop supports multiple compression methods for channel data to reduce file size.
Supported compression methods:
- RAW (
Compression.RAW): Uncompressed raw pixel data - RLE (
Compression.RLE): Apple PackBits run-length encoding - ZIP (
Compression.ZIP): ZIP/Deflate compression without prediction - ZIP_WITH_PREDICTION (
Compression.ZIP_WITH_PREDICTION): ZIP with delta encoding
The RLE codec includes both a pure Python implementation and a Cython-optimized version (_rle.pyx) that provides significant performance improvements. The Cython version is used automatically when available, with graceful fallback to pure Python.
Key functions:
compress(): Compress raw pixel data using specified methoddecompress(): Decompress pixel data back to raw bytesencode_rle(): RLE encoding for a single channeldecode_rle(): RLE decoding for a single channel
Example usage:
from psd_tools.compression import compress, decompress
from psd_tools.constants import Compression
# Compress raw channel data
compressed = compress(
data=raw_pixels,
compression=Compression.RLE,
width=100,
height=100,
depth=8,
version=1
)
# Decompress back to raw data
raw_pixels = decompress(
data=compressed,
compression=Compression.RLE,
width=100,
height=100,
depth=8,
version=1
)
Performance notes ๐ (aka the tea on when to use what):
- RLE is most effective for images with large uniform areas
- ZIP with prediction works well for continuous-tone images
- The Cython RLE codec can be 10-100x faster than pure Python
- Compression method is chosen per-channel when saving PSD files
The compression module handles various bit depths (8, 16, 32-bit per channel) and implements delta encoding for improved compression ratios on certain image types.
This module provides compression and decompression codecs for PSD channel data.
โจ Compression Functions โจ
psd_tools.compression.compress(data: bytes, compression: Compression <#psd_tools.constants.Compression>, width: int, height: int, depth: int, version: int = 1) -> bytesโ Compress raw data. Squish it, bestie. ๐
Parameters
dataโ raw data bytes to write.compressionโ compression type, seeCompression <#psd_tools.constants.Compression>.widthโ width.heightโ height.depthโ bit depth of the pixel.versionโ psd file version.
Returns โ compressed data bytes. ๐
psd_tools.compression.decompress(data: bytes, compression: Compression <#psd_tools.constants.Compression>, width: int, height: int, depth: int, version: int = 1) -> bytesโ Decompress raw data. Unsquish. Reverse girliepop. ๐ฆ
Parameters
dataโ compressed data bytes.compressionโ compression type, seeCompression <#psd_tools.constants.Compression>.widthโ width in pixels; must be in[1, 300000].heightโ height in pixels; must be in[1, 300000].depthโ bit depth of the pixel; must be one of1,8,16,32.versionโ psd file version.
Returns โ decompressed data bytes.
Raises ValueError โ if width, height, or depth are out of range. ๐จ Like, respect the limits or get an exception, periodt.
๐ฆ RLE Codec ๐ฆ
psd_tools.compression.encode_rle(data: bytes, width: int, height: int, depth: int, version: int) -> bytes
psd_tools.compression.decode_rle(data: bytes, width: int, height: int, depth: int, version: int) -> bytes
The RLE (Run-Length Encoding) codec implements Apple PackBits compression. A Cython-optimized version (_rle.pyx) is used when available, providing 10-100x performance improvement over the pure Python fallback. Basically if you got the Cython build, you're eating GOOD. ๐ฅ
๐ Prediction Encoding ๐
psd_tools.compression.encode_prediction(data: bytes | bytearray, w: int, h: int, depth: int) -> bytes
psd_tools.compression.decode_prediction(data: bytes, w: int, h: int, depth: int) -> bytes
Prediction encoding applies delta compression before ZIP compression, improving compression ratios for continuous-tone images. Supports 8, 16, and 32-bit depths. โญ
๐ psd_tools.constants ๐
Various constants for psd_tools
๐ธ BlendMode ๐ธ
class psd_tools.constants.BlendMode(*values) โ Blend modes. The whole squad of ways your layers can mix together, no cap.
COLOR = b'colr'COLOR_BURN = b'idiv'COLOR_DODGE = b'div 'DARKEN = b'dark'DARKER_COLOR = b'dkCl'DIFFERENCE = b'diff'DISSOLVE = b'diss'DIVIDE = b'fdiv'EXCLUSION = b'smud'HARD_LIGHT = b'hLit'HARD_MIX = b'hMix'HUE = b'hue 'LIGHTEN = b'lite'LIGHTER_COLOR = b'lgCl'LINEAR_BURN = b'lbrn'LINEAR_DODGE = b'lddg'LINEAR_LIGHT = b'lLit'LUMINOSITY = b'lum 'MULTIPLY = b'mul 'NORMAL = b'norm'OVERLAY = b'over'PASS_THROUGH = b'pass'PIN_LIGHT = b'pLit'SATURATION = b'sat 'SCREEN = b'scrn'SOFT_LIGHT = b'sLit'SUBTRACT = b'fsub'VIVID_LIGHT = b'vLit'
๐ ChannelID ๐
class psd_tools.constants.ChannelID(*values) โ Channel types.
CHANNEL_0 = 0CHANNEL_1 = 1CHANNEL_2 = 2CHANNEL_3 = 3CHANNEL_4 = 4CHANNEL_5 = 5CHANNEL_6 = 6CHANNEL_7 = 7CHANNEL_8 = 8CHANNEL_9 = 9REAL_USER_LAYER_MASK = -3TRANSPARENCY_MASK = -1USER_LAYER_MASK = -2
โจ Clipping โจ
class psd_tools.constants.Clipping(*values) โ Clipping.
BASE = 0NON_BASE = 1
๐ ColorMode ๐
class psd_tools.constants.ColorMode(*values) โ Color mode.
BITMAP = 0CMYK = 4DUOTONE = 8GRAYSCALE = 1INDEXED = 2LAB = 9MULTICHANNEL = 7RGB = 3- static
channels(value: ColorMode <#psd_tools.constants.ColorMode>, alpha: bool = False) -> intโ hands you back the channel count as anint. ๐
๐ฆ ColorSpaceID ๐ฆ
class psd_tools.constants.ColorSpaceID(*values) โ Color space types.
CMYK = 2GRAYSCALE = 8HSB = 1LAB = 7RGB = 0
๐ CompatibilityMode ๐
class psd_tools.constants.CompatibilityMode(*values) โ Compatibility modes that describe how compositing and layer control should attempt to behave.
CLIP_STUDIO_PAINT = 3DEFAULT = 1GIMP = 4KRITA = 5PAINT_TOOL_SAI = 2PHOTOSHOP = 1
๐ฅ Compression ๐ฅ
class psd_tools.constants.Compression(*values) โ Compression modes.
Compression. 0 = Raw Data, 1 = RLE compressed, 2 = ZIP without prediction, 3 = ZIP with prediction.
RAW = 0RLE = 1ZIP = 2ZIP_WITH_PREDICTION = 3
๐ EffectOSType ๐
class psd_tools.constants.EffectOSType(*values) โ OS Type keys for Layer Effects.
BEVEL = b'bevl'COMMON_STATE = b'cmnS'DROP_SHADOW = b'dsdw'INNER_GLOW = b'iglw'INNER_SHADOW = b'isdw'OUTER_GLOW = b'oglw'SOLID_FILL = b'sofi'
๐ GlobalLayerMaskKind ๐
class psd_tools.constants.GlobalLayerMaskKind(*values) โ Global layer mask kind.
COLOR_PROTECTED = 1COLOR_SELECTED = 0PER_LAYER = 128
๐ง LinkedLayerType ๐ง
class psd_tools.constants.LinkedLayerType(*values) โ Linked layer types.
ALIAS = b'liFA'DATA = b'liFD'EXTERNAL = b'liFE'
๐ PathResourceID ๐
class psd_tools.constants.PathResourceID(*values)
CLIPBOARD = 7CLOSED_KNOT_LINKED = 1CLOSED_KNOT_UNLINKED = 2CLOSED_LENGTH = 0INITIAL_FILL = 8OPEN_KNOT_LINKED = 4OPEN_KNOT_UNLINKED = 5OPEN_LENGTH = 3PATH_FILL = 6
๐ซถ PlacedLayerType ๐ซถ
class psd_tools.constants.PlacedLayerType(*values)
IMAGE_STACK = 3RASTER = 2UNKNOWN = 0VECTOR = 1
๐ญ PrintScaleStyle ๐ญ
class psd_tools.constants.PrintScaleStyle(*values) โ Print scale style.
CENTERED = 0SIZE_TO_FIT = 1USER_DEFINED = 2
๐ Resource ๐
class psd_tools.constants.Resource(*values) โ Image resource keys.
Heads up bestie: the following is not defined for performance reasons. Not me leaving stuff out on purpose โ it's for the vibes (and the speed). ๐
PATH_INFO_10toPATH_INFO_989corresponding to2010-2989PLUGIN_RESOURCES_10toPLUGIN_RESOURCES_989corresponding to4010-4989
And now, the full roster:
ALPHA_IDENTIFIERS = 1053ALPHA_NAMES_PASCAL = 1006ALPHA_NAMES_UNICODE = 1045ALTERNATE_DUOTONE_COLORS = 1066ALTERNATE_SPOT_COLORS = 1067AUTO_SAVE_FILE_PATH = 1086AUTO_SAVE_FORMAT = 1087BACKGROUND_COLOR = 1010BORDER_INFO = 1009CAPTION_DIGEST = 1061CAPTION_PASCAL = 1008CLIPPING_PATH_NAME = 2999COLOR_HALFTONING_INFO = 1013COLOR_SAMPLERS_RESOURCE = 1073COLOR_SAMPLERS_RESOURCE_OBSOLETE = 1038COLOR_TRANSFER_FUNCTION = 1016COPYRIGHT_FLAG = 1034COUNT_INFO = 1080DISPLAY_INFO = 1077DISPLAY_INFO_OBSOLETE = 1007DUOTONE_HALFTONING_INFO = 1014DUOTONE_IMAGE_INFO = 1018DUOTONE_TRANSFER_FUNCTION = 1017EFFECTIVE_BW = 1019EFFECTS_VISIBLE = 1042EPS_OPTIONS = 1021EXIF_DATA_1 = 1058EXIF_DATA_3 = 1059GLOBAL_ALTITUDE = 1049GLOBAL_ANGLE = 1037GRAYSCALE_HALFTONING_INFO = 1012GRAYSCALE_TRANSFER_FUNCTION = 1015GRID_AND_GUIDES_INFO = 1032HDR_TONING_INFO = 1070ICC_PROFILE = 1039ICC_UNTAGGED_PROFILE = 1041IDS_SEED_NUMBER = 1044IMAGE_MODE_RAW = 1029IMAGE_READY_7_ROLLOVER_EXPANDED_STATE = 7003IMAGE_READY_DATA_SETS = 7001IMAGE_READY_DEFAULT_SELECTED_STATE = 7002IMAGE_READY_ROLLOVER_EXPANDED_STATE = 7004IMAGE_READY_SAVE_LAYER_SETTINGS = 7005IMAGE_READY_VARIABLES = 7000IMAGE_READY_VERSION = 7006INDEXED_COLOR_TABLE_COUNT = 1046IPTC_NAA = 1028JPEG_QUALITY = 1030JUMP_TO_XPEP = 1052LAYER_COMPS = 1065LAYER_GROUPS_ENABLED_ID = 1072LAYER_GROUP_INFO = 1026LAYER_SELECTION_IDS = 1069LAYER_STATE_INFO = 1024LIGHTROOM_WORKFLOW = 8000MAC_NSPRINTINFO = 1084MAC_PAGE_FORMAT_INFO = 1002MAC_PRINT_MANAGER_INFO = 1001MEASUREMENT_SCALE = 1074OBSOLETE1 = 1000OBSOLETE2 = 1003OBSOLETE3 = 1020OBSOLETE4 = 1023OBSOLETE5 = 1027ONION_SKINS = 1078ORIGIN_PATH_INFO = 3000PATH_INFO_0 = 2000PATH_INFO_1 = 2001PATH_INFO_2 = 2002PATH_INFO_3 = 2003PATH_INFO_4 = 2004PATH_INFO_5 = 2005PATH_INFO_6 = 2006PATH_INFO_7 = 2007PATH_INFO_8 = 2008PATH_INFO_9 = 2009PATH_INFO_990 = 2990PATH_INFO_991 = 2991PATH_INFO_992 = 2992PATH_INFO_993 = 2993PATH_INFO_994 = 2994PATH_INFO_995 = 2995PATH_INFO_996 = 2996PATH_INFO_997 = 2997PATH_SELECTION_STATE = 1088PIXEL_ASPECT_RATIO = 1064PLUGIN_RESOURCE_0 = 4000PLUGIN_RESOURCE_1 = 4001PLUGIN_RESOURCE_2 = 4002PLUGIN_RESOURCE_3 = 4003PLUGIN_RESOURCE_4 = 4004PLUGIN_RESOURCE_4990 = 4990PLUGIN_RESOURCE_4991 = 4991PLUGIN_RESOURCE_4992 = 4992PLUGIN_RESOURCE_4993 = 4993PLUGIN_RESOURCE_4994 = 4994PLUGIN_RESOURCE_4995 = 4995PLUGIN_RESOURCE_4996 = 4996PLUGIN_RESOURCE_4997 = 4997PLUGIN_RESOURCE_4998 = 4998PLUGIN_RESOURCE_4999 = 4990PLUGIN_RESOURCE_5 = 4005PLUGIN_RESOURCE_6 = 4006PLUGIN_RESOURCE_7 = 4007PLUGIN_RESOURCE_8 = 4008PLUGIN_RESOURCE_9 = 4009PRINT_FLAGS = 1011PRINT_FLAGS_INFO = 10000PRINT_INFO_CS2 = 1071PRINT_INFO_CS5 = 1082PRINT_SCALE = 1062PRINT_STYLE = 1083QUICK_MASK_INFO = 1022RESOLUTION_INFO = 1005SHEET_DISCLOSURE = 1076SLICES = 1050SPOT_HALFTONE = 1043THUMBNAIL_RESOURCE = 1036THUMBNAIL_RESOURCE_PS4 = 1033TIMELINE_INFO = 1075TRANSPARENCY_INDEX = 1047URL = 1035URL_LIST = 1054VERSION_INFO = 1057WATERMARK = 1040WINDOWS_DEVMODE = 1085WORKFLOW_URL = 1051WORKING_PATH = 1025XMP_METADATA = 1060
okay bestie quick heads-up before you @ me: yes, PLUGIN_RESOURCE_4999 = 4990 โ that is literally what it says, we do not fix it, we do not touch it, we just report it ๐
static is_path_info(value: int) -> bool
static is_plugin_resource(value: int) -> bool
SectionDivider ๐
class psd_tools.constants.SectionDivider(*values)
BOUNDING_SECTION_DIVIDER = 3CLOSED_FOLDER = 2OPEN_FOLDER = 1OTHER = 0
Tag ๐ท๏ธโจ
class psd_tools.constants.Tag(*values)
Tagged blocks keys. iykyk.
ALPHA = b'Alph'ANIMATION_EFFECTS = b'anFX'ANNOTATIONS = b'Anno'ARTBOARD_DATA1 = b'artb'ARTBOARD_DATA2 = b'artd'ARTBOARD_DATA3 = b'abdd'BLACK_AND_WHITE = b'blwh'BLEND_CLIPPING_ELEMENTS = b'clbl'BLEND_FILL_OPACITY = b'iOpa'BLEND_INTERIOR_ELEMENTS = b'infx'BRIGHTNESS_AND_CONTRAST = b'brit'CAI = b'CAI 'CHANNEL_BLENDING_RESTRICTIONS_SETTING = b'brst'CHANNEL_MIXER = b'mixr'COLOR_BALANCE = b'blnc'COLOR_LOOKUP = b'clrL'COMPOSITOR_INFO = b'cinf'CONTENT_GENERATOR_EXTRA_DATA = b'CgEd'CURVES = b'curv'EFFECTS_LAYER = b'lrFX'EXPORT_SETTING1 = b'extd'EXPORT_SETTING2 = b'extn'EXPOSURE = b'expA'FILTER_EFFECTS1 = b'FXid'FILTER_EFFECTS2 = b'FEid'FILTER_EFFECTS3 = b'FELS'FILTER_MASK = b'FMsk'FOREIGN_EFFECT_ID = b'ffxi'FRAMED_GROUP = b'frgb'GENI = b'GenI'GRADIENT_FILL_SETTING = b'GdFl'GRADIENT_MAP = b'grdm'HUE_SATURATION = b'hue2'HUE_SATURATION_V4 = b'hue 'INVERT = b'nvrt'KNOCKOUT_SETTING = b'knko'LAYER = b'Layr'LAYER_16 = b'Lr16'LAYER_32 = b'Lr32'LAYER_ID = b'lyid'LAYER_MASK_AS_GLOBAL_MASK = b'lmgm'LAYER_NAME_SOURCE_SETTING = b'lnsr'LAYER_VERSION = b'lyvr'LEVELS = b'levl'LINKED_LAYER1 = b'lnkD'LINKED_LAYER2 = b'lnk2'LINKED_LAYER3 = b'lnk3'LINKED_LAYER_EXTERNAL = b'lnkE'METADATA_SETTING = b'shmd'NESTED_SECTION_DIVIDER_SETTING = b'lsdk'OBJECT_BASED_EFFECTS_LAYER_INFO = b'lfx2'OBJECT_BASED_EFFECTS_LAYER_INFO_V0 = b'lmfx'OBJECT_BASED_EFFECTS_LAYER_INFO_V1 = b'lfxs'OCIO = b'OCIO'PATT = b'patt'PATTERNS1 = b'Patt'PATTERNS2 = b'Pat2'PATTERNS3 = b'Pat3'PATTERN_DATA = b'shpa'PATTERN_FILL_SETTING = b'PtFl'PHOTO_FILTER = b'phfl'PIXEL_SOURCE_DATA1 = b'PxSc'PIXEL_SOURCE_DATA2 = b'PxSD'PLACED_LAYER1 = b'plLd'PLACED_LAYER2 = b'PlLd'POSTERIZE = b'post'PROTECTED_SETTING = b'lspf'REFERENCE_POINT = b'fxrp'SAVING_MERGED_TRANSPARENCY = b'Mtrn'SAVING_MERGED_TRANSPARENCY16 = b'Mt16'SAVING_MERGED_TRANSPARENCY32 = b'Mt32'SECTION_DIVIDER_SETTING = b'lsct'SELECTIVE_COLOR = b'selc'SHEET_COLOR_SETTING = b'lclr'SMART_OBJECT_LAYER_DATA1 = b'SoLd'SMART_OBJECT_LAYER_DATA2 = b'SoLE'SOLID_COLOR_SHEET_SETTING = b'SoCo'TEXT_ENGINE_DATA = b'Txt2'THRESHOLD = b'thrs'TRANSPARENCY_SHAPES_LAYER = b'tsly'TYPE_TOOL_INFO = b'tySh'TYPE_TOOL_OBJECT_SETTING = b'TySh'UNICODE_LAYER_NAME = b'luni'UNICODE_PATH_NAME = b'pths'USER_MASK = b'LMsk'USING_ALIGNED_RENDERING = b'sn2P'VECTOR_MASK_AS_GLOBAL_MASK = b'vmgm'VECTOR_MASK_SETTING1 = b'vmsk'VECTOR_MASK_SETTING2 = b'vsms'VECTOR_ORIGINATION_DATA = b'vogk'VECTOR_ORIGINATION_UNKNOWN = b'vowv'VECTOR_STROKE_CONTENT_DATA = b'vscg'VECTOR_STROKE_DATA = b'vstk'VIBRANCE = b'vibA'
bestie. look atCAI = b'CAI 'andHUE_SATURATION_V4 = b'hue '. those trailing spaces are REAL and they are LOAD-BEARING. do not let your formatter eat them ๐
TextType ๐
class psd_tools.constants.TextType(*values)
Type of text.
PARAGRAPH = 1POINT = 0
psd_tools.psd ๐
Low-level API that translates binary data to Python structure.
All the data structure in this subpackage inherits from one of the object defined in psd_tools.psd.base module.
PSD ๐
class psd_tools.psd.PSD(header: FileHeader = NOTHING, color_mode_data: ColorModeData = NOTHING, image_resources: ImageResources = NOTHING, layer_and_mask_information: LayerAndMaskInformation = NOTHING, image_data: ImageData = NOTHING)
Low-level PSD file structure that resembles the specification at https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/.
Example:
from psd_tools.psd import PSD
with open(input_file, 'rb') as f:
psd = PSD.read(f)
with open(output_file, 'wb') as f:
psd.write(f)
headerโ SeeFileHeader(psd_tools.psd.header.FileHeader).color_mode_dataโ SeeColorModeData(psd_tools.psd.color_mode_data.ColorModeData).image_resourcesโ SeeImageResources(psd_tools.psd.image_resources.ImageResources).layer_and_mask_informationโ SeeLayerAndMaskInformation(psd_tools.psd.layer_and_mask.LayerAndMaskInformation).image_dataโ SeeImageData(psd_tools.psd.image_data.ImageData).
psd_tools.psd.base ๐งฑ
Base data structures intended for inheritance.
All the data objects in this subpackage inherit from the base classes here. That means, all the data structures in the psd_tools.psd subpackage implements the methods of BaseElement for serialization and decoding.
Objects that inherit from the BaseElement typically gets attrs (at https://www.attrs.org/en/stable/index.html) decoration to have data fields.
BaseElement ๐
class psd_tools.psd.base.BaseElement
Base element of various PSD file structs. All the data objects in psd_tools.psd subpackage inherit from this class.
classmethod read(cls, fp)โ Read the element from a file-like object.write(self, fp)โ Write the element to a file-like object.classmethod frombytes(self, data, *args, **kwargs)โ Read the element from bytes.tobytes(self, *args, **kwargs)โ Write the element to bytes.validate(self)โ Validate the attribute.
EmptyElement ๐ซ
class psd_tools.psd.base.EmptyElement
Empty element that does not have a value.
ValueElement ๐
class psd_tools.psd.base.ValueElement(value: object = None)
Single value wrapper that has a value attribute.
Pretty printing shows the internal value by default. Inherit with @define(repr=False) decorator to keep this behavior.
valueโ Internal value.
NumericElement ๐ข
class psd_tools.psd.base.NumericElement(value=0.0)
Single value element that has a numeric value attribute.
IntegerElement ๐
class psd_tools.psd.base.IntegerElement(value=0)
Single integer value element that has a value attribute.
Use with @define(repr=False) decorator.
ShortIntegerElement ๐ฉณ
class psd_tools.psd.base.ShortIntegerElement(value=0)
Single short integer element that has a value attribute.
Use with @define(repr=False) decorator.
ByteElement ๐ง
class psd_tools.psd.base.ByteElement(value=0)
Single 1-byte integer element that has a value attribute.
Use with @define(repr=False) decorator.
BooleanElement โ
class psd_tools.psd.base.BooleanElement(value=False)
Single bool value element that has a value attribute.
Use with @define(repr=False) decorator.
StringElement ๐ชข
class psd_tools.psd.base.StringElement(value: str = '')
Single unicode string.
valueโstrvalue
ListElement ๐
class psd_tools.psd.base.ListElement(items=NOTHING)
List-like element that has items list.
DictElement ๐๏ธ
class psd_tools.psd.base.DictElement(items=NOTHING)
Dict-like element that has items OrderedDict.
psd_tools.psd.color_mode_data ๐จ
Color mode data structure.
ColorModeData ๐
class psd_tools.psd.color_mode_data.ColorModeData(value: bytes = b'')
Color mode data section of the PSD file.
For indexed color images the data is the color table for the image in a non-interleaved order.
Duotone images also have this data, but the data format is undocumented.
interleave() -> bytesโ Returns interleaved color table in bytes.
psd_tools.psd.descriptor ๐ฆ
Descriptor data structure.
Descriptors are basic data structure used throughout PSD files. Descriptor is one kind of serialization protocol for data objects, and enum classes in psd_tools.terminology or bytes indicates what kind of descriptor it is.
okay so real quick on that class ID situation: it can be a pre-defined enum if the tag is 4-byte length, or plain bytes if the length is arbitrary ๐ซ They depend on the internal version of Adobe Photoshop but the detail is unknown โ no cap, nobody knows.
Pretty printing is the best approach to check the descriptor content:
from IPython.pretty import pprint
pprint(descriptor)
Alias
class psd_tools.psd.descriptor.Alias(value: bytes = b'\x00\x00\x00\x00')
Alias structure, equivalent to RawData. ๐
Bool
class psd_tools.psd.descriptor.Bool(value=False)
Bool structure.
valueโ bool value
Class
class psd_tools.psd.descriptor.Class(name: str = '', classID: bytes = b'\x00\x00\x00\x00')
Class structure.
nameโ str valueclassIDโ bytes in Klass (psd_tools.terminology.Klass)
Class1
class psd_tools.psd.descriptor.Class1(name: str = '', classID: bytes = b'\x00\x00\x00\x00')
Class structure, equivalent to Class. Same energy, different name, bestie ๐ซถ
Class2
class psd_tools.psd.descriptor.Class2(name: str = '', classID: bytes = b'\x00\x00\x00\x00')
Class structure, equivalent to Class.
Class3
class psd_tools.psd.descriptor.Class3(name: str = '', classID: bytes = b'\x00\x00\x00\x00')
Class structure, equivalent to Class. yes, there are three of them, and yes, they're all the same, we don't make the rules ๐
Descriptor
class psd_tools.psd.descriptor.Descriptor(items=NOTHING, name: str = '', classID: bytes = b'null')
Dict-like descriptor structure. it's giving dictionary but make it Photoshop
Key values can be 4-character bytes in Key (psd_tools.terminology.Key) or arbitrary length bytes. Supports direct access by Key (psd_tools.terminology.Key).
Example:
from psd_tools.terminology import Key
descriptor[Key.Enabled]
for key in descriptor:
print(descriptor[key])
nameโ strclassIDโ bytes in Klass (psd_tools.terminology.Klass)
Double
class psd_tools.psd.descriptor.Double(value=0.0)
Double structure.
valueโ float value
Enumerated
class psd_tools.psd.descriptor.Enumerated(typeID: bytes = b'\x00\x00\x00\x00', enum: bytes = b'\x00\x00\x00\x00')
Enum structure.
typeIDโ bytes in Type (psd_tools.terminology.Type)enumโ bytes in Enum (psd_tools.terminology.Enum)get_name() -> strโ Get enum name. ๐
EnumeratedReference
class psd_tools.psd.descriptor.EnumeratedReference(name: str = '', classID: bytes = b'\x00\x00\x00\x00', typeID: bytes = b'\x00\x00\x00\x00', enum: bytes = b'\x00\x00\x00\x00')
Enumerated reference structure.
nameโ str valueclassIDโ bytes in Klass (psd_tools.terminology.Klass)typeIDโ bytes in Type (psd_tools.terminology.Type)enumโ bytes in Enum (psd_tools.terminology.Enum)
GlobalObject
class psd_tools.psd.descriptor.GlobalObject(items=NOTHING, name: str = '', classID: bytes = b'null')
Global object structure, equivalent to Descriptor.
Identifier
class psd_tools.psd.descriptor.Identifier(value=0)
Identifier, equivalent to Integer.
Index
class psd_tools.psd.descriptor.Index(value=0)
Index, equivalent to Integer.
Integer
class psd_tools.psd.descriptor.Integer(value=0)
Integer structure.
valueโ int value
LargeInteger
class psd_tools.psd.descriptor.LargeInteger(value=0)
LargeInteger structure. big number energy ๐ฅ
valueโ int value
List
class psd_tools.psd.descriptor.List(items=NOTHING)
List structure.
Example:
for item in list_value:
print(item)
Name
class psd_tools.psd.descriptor.Name(name: str = '', classID: bytes = b'\x00\x00\x00\x00', value: str = '')
Name structure (Undocumented ๐).
nameโ strclassIDโ bytes in Klass (psd_tools.terminology.Klass)valueโ str
ObjectArray
class psd_tools.psd.descriptor.ObjectArray(items=NOTHING, items_count: int = 0, name: str = '', classID: bytes = b'null')
Object array structure, almost equivalent to Descriptor.
items_countโ int valuenameโ str valueclassIDโ bytes in Klass (psd_tools.terminology.Klass)
Property
class psd_tools.psd.descriptor.Property(name: str = '', classID: bytes = b'\x00\x00\x00\x00', keyID: bytes = b'\x00\x00\x00\x00')
Property structure.
nameโ str valueclassIDโ bytes in Klass (psd_tools.terminology.Klass)keyIDโ bytes in Key (psd_tools.terminology.Key)
Offset
class psd_tools.psd.descriptor.Offset(name: str = '', classID: bytes = b'\x00\x00\x00\x00', value: int = 0)
Offset structure.
nameโ str valueclassIDโ bytes in Klass (psd_tools.terminology.Klass)valueโ int value
Path
class psd_tools.psd.descriptor.Path(value: bytes = b'\x00\x00\x00\x00')
Undocumented path structure, equivalent to RawData. ๐
RawData
class psd_tools.psd.descriptor.RawData(value: bytes = b'\x00\x00\x00\x00')
RawData structure.
valueโ bytes value
Reference
class psd_tools.psd.descriptor.Reference(items=NOTHING)
Reference structure, equivalent to List.
String
class psd_tools.psd.descriptor.String(value: str = '')
String structure.
valueโ str value
UnitFloat
class psd_tools.psd.descriptor.UnitFloat(value: float = 0.0, unit: Unit = Unit._None)
Unit float structure. (Unit here is psd_tools.terminology.Unit โจ)
unitโ unit of the value inUnitorEnumvalueโ float value
UnitFloats
class psd_tools.psd.descriptor.UnitFloats(unit: Unit = Unit._None, values: list = NOTHING)
Unit floats structure. (Unit here is psd_tools.terminology.Unit ๐ธ)
unitโ unit of the value inUnitorEnumvaluesโ List of float values
<butterfly>psd_tools.psd.engine_data</butterfly>
EngineData structure.
PSD file embeds text formatting data in its own markup language referred EngineData. The format looks like the following:
<<
/EngineDict
<<
/Editor
<<
/Text (หหMake a change and save.)
>>
>>
/Font
<<
/Name (หหHelveticaNeue-Light)
/FillColor
<<
/Type 1
/Values [ 1.0 0.0 0.0 0.0 ]
>>
/StyleSheetSet [
<<
/Name (หหNormal RGB)
>>
]
>>
>>
bestie that's the whole markup language right there, brackets inside brackets, we love a nesting moment ๐ฆ
EngineData
class psd_tools.psd.engine_data.EngineData(items=NOTHING)
Dict-like element.
TYPE_TOOL_OBJECT_SETTING tagged block contains this object in its descriptor.
EngineData2
class psd_tools.psd.engine_data.EngineData2(items=NOTHING)
Dict-like element.
TEXT_ENGINE_DATA tagged block has this object.
Bool
class psd_tools.psd.engine_data.Bool(value=False)
Bool element.
Dict
class psd_tools.psd.engine_data.Dict(items=NOTHING)
Dict-like element.
Float
class psd_tools.psd.engine_data.Float(value=0.0)
Float element.
Integer
class psd_tools.psd.engine_data.Integer(value=0)
Integer element.
List
class psd_tools.psd.engine_data.List(items=NOTHING)
List-like element.
Property
class psd_tools.psd.engine_data.Property(value: object = None)
Property element.
String
class psd_tools.psd.engine_data.String(value: object = None)
String element.
<butterfly>psd_tools.psd.effects_layer</butterfly>
Effects layer structure.
โ ๏ธ heads up bestie: the structures in this module is obsolete, and object-based layer effects are stored in tagged blocks. so like, iconic but retired ๐
EffectsLayer
class psd_tools.psd.effects_layer.EffectsLayer(items=NOTHING, version: int = 0)
Dict-like EffectsLayer structure. See psd_tools.constants.EffectOSType for available keys.
version
CommonStateInfo
class psd_tools.psd.effects_layer.CommonStateInfo(version: int = 0, visible: int = 1)
Effects layer common state info.
versionvisible
ShadowInfo
class psd_tools.psd.effects_layer.ShadowInfo(version: int = 0, blur: int = 0, intensity: int = 0, angle: int = 0, distance: int = 0, color: Color = NOTHING, blend_mode=BlendMode.NORMAL, enabled: int = 0, use_global_angle: int = 0, opacity: int = 0, native_color: Color = NOTHING)
Effects layer shadow info.
versionblurintensityangledistancecolorblend_modeenableduse_global_angleopacitynative_color
OuterGlowInfo
class psd_tools.psd.effects_layer.OuterGlowInfo(version: int = 0, blur: int = 0, intensity: int = 0, color: Color = NOTHING, blend_mode=BlendMode.NORMAL, enabled: int = 0, opacity: int = 0, native_color: object = None)
Effects layer outer glow info. glow up, literally โจ
versionblurintensitycolorblend_modeenabledopacitynative_color
InnerGlowInfo
class psd_tools.psd.effects_layer.InnerGlowInfo(version: int = 0, blur: int = 0, intensity: int = 0, color: Color = NOTHING, blend_mode=BlendMode.NORMAL, enabled: int = 0, opacity: int = 0, invert: int | None = None, native_color: object | None = None)
Effects layer inner glow info.
versionblurintensitycolorblend_modeenabledopacityinvertnative_color
BevelInfo
class psd_tools.psd.effects_layer.BevelInfo(version: int = 0, angle: int = 0, depth: int = 0, blur: int = 0, highlight_blend_mode=BlendMode.NORMAL, shadow_blend_mode=BlendMode.NORMAL, highlight_color: Color = NOTHING, shadow_color: Color = NOTHING, bevel_style: int = 0, highlight_opacity: int = 0, shadow_opacity: int = 0, enabled: int = 0, use_global_angle: int = 0, direction: int = 0, real_highlight_color: object = None, real_shadow_color: object = None)
Effects layer bevel info. the bevel really said let me give you sixteen parameters ๐ซถ
versionangledepthblurhighlight_blend_modeshadow_blend_modehighlight_colorshadow_colorhighlight_opacityshadow_opacityenableduse_global_angledirectionreal_hightlight_colorreal_shadow_color
โจ SolidFillInfo
class psd_tools.psd.effects_layer.SolidFillInfo(version: int = 2, blend_mode=BlendMode.NORMAL, color: Color = NOTHING, opacity: int = 0, enabled: int = 0, native_color: Color = NOTHING)
Bestie, this one is the Effects layer inner glow info ๐. Its lil attribute squad is:
versionblend_modecoloropacityenablednative_color
๐ฆ psd_tools.psd.filter_effects
The Filter effects structure. That's the whole vibe. Periodt.
FilterEffects
class psd_tools.psd.filter_effects.FilterEffects(items=NOTHING, version: int = 1)
A list-like FilterEffects structure ๐ซถ โ and it says, and I quote: See FilterEffect. Its attributes:
version
FilterEffect
class psd_tools.psd.filter_effects.FilterEffect(uuid: str | None = None, version: int | None = None, rectangle: tuple | None = None, depth: int | None = None, max_channels: int | None = None, channels: list | None = None, extra: object | None = None)
The FilterEffect structure, no cap ๐ง. Attributes:
uuidversionrectangledepthmax_channelschannelsโ literally a List ofFilterEffectChannel.extraโ SeeFilterEffectExtra.
FilterEffectChannel
class psd_tools.psd.filter_effects.FilterEffectChannel(is_written: int = 0, compression: int | None = None, data: bytes = b'')
FilterEffectChannel structure ๐
. Its attributes:
is_writtencompressiondata
FilterEffectExtra
class psd_tools.psd.filter_effects.FilterEffectExtra(is_written: int = 0, rectangle=NOTHING, compression: int = 0, data: bytes = b'')
FilterEffectExtra structure ๐ธ. Its attributes:
is_writtenrectanglecompressiondata
๐ psd_tools.psd.header
The File header structure. We love a header.
FileHeader
class psd_tools.psd.header.FileHeader(signature: bytes = b'8BPS', version: int = 1, channels: int = 4, height: int = 64, width: int = 64, depth: int = 8, color_mode=ColorMode.RGB)
This is the Header section of the PSD file โ the main character intro, if you will โจ.
Example, ok? Slay:
from psd_tools.psd.header import FileHeader
from psd_tools.constants import ColorMode
header = FileHeader(channels=2, height=359, width=400, depth=8,
color_mode=ColorMode.GRAYSCALE)
And now the attributes, one by one, no skipping bestie:
signatureโ Signature: always equal tob'8BPS'.versionโ Version number. PSD is1, and PSB is2.channelsโ The number of channels in the image, including any user-defined alpha channel.heightโ The height of the image in pixels.widthโ The width of the image in pixels.depthโ The number of bits per channel.color_modeโ The color mode of the file. SeeColorMode <#psd_tools.constants.ColorMode>.
๐ psd_tools.psd.image_data
Image data section structure. ImageData corresponds to the last section of the PSD/PSB file where a composited image is stored ๐. So when the file does not contain layers, this is the only place pixels are saved. That's it. That's the whole thing. Iconic.
ImageData
class psd_tools.psd.image_data.ImageData(compression=Compression.RAW, data: bytes = b'')
Merged channel image data ๐ฅ. Attributes:
compressionโ SeeCompression <#psd_tools.constants.Compression>.dataโ bytes as compressed in the compression flag.
get_data(header: FileHeader <#psd_tools.psd.header.FileHeader>, split: bool = True) -> list[bytes] | bytes
Get decompressed data ๐ซง.
Parameters:
- header โ See
FileHeader <#psd_tools.psd.header.FileHeader>.
Returns:
- list of bytes corresponding each channel.
classmethod new(header: FileHeader <#psd_tools.psd.header.FileHeader>, color: int | Sequence[int] = 0, compression: Compression <#psd_tools.constants.Compression> = Compression.RAW) -> T
Create a new image data object โจ.
Parameters:
- header โ
FileHeader. - compression โ compression type.
- color โ default color.
intor iterable for channel length.
set_data(data: Sequence[bytes], header: FileHeader <#psd_tools.psd.header.FileHeader>) -> int
Set raw data and compress ๐ .
Parameters:
- data โ list of raw data bytes corresponding channels.
- compression โ compression type, see
Compression <#psd_tools.constants.Compression>. - header โ See
FileHeader <#psd_tools.psd.header.FileHeader>.
Returns:
- length of compressed data.
๐ psd_tools.psd.image_resources
Image resources section structure, bestie. Image resources are used to store non-pixel data associated with images, such as pen tool paths or slices ๐.
See Resource <#psd_tools.constants.Resource> to check available resource names.
Example:
from psd_tools.constants import Resource
version_info = psd.image_resources.get_data(Resource.VERSION_INFO)
The following resources are plain bytes, fr fr:
Resource.OBSOLETE1: 1000
Resource.MAC_PRINT_MANAGER_INFO: 1001
Resource.MAC_PAGE_FORMAT_INFO: 1002
Resource.OBSOLETE2: 1003
Resource.DISPLAY_INFO_OBSOLETE: 1007
Resource.BORDER_INFO: 1009
Resource.DUOTONE_IMAGE_INFO: 1018
Resource.EFFECTIVE_BW: 1019
Resource.OBSOLETE3: 1020
Resource.EPS_OPTIONS: 1021
Resource.QUICK_MASK_INFO: 1022
Resource.OBSOLETE4: 1023
Resource.WORKING_PATH: 1025
Resource.OBSOLETE5: 1027
Resource.IPTC_NAA: 1028
Resource.IMAGE_MODE_RAW: 1029
Resource.JPEG_QUALITY: 1030
Resource.URL: 1035
Resource.COLOR_SAMPLERS_RESOURCE_OBSOLETE: 1038
Resource.ICC_PROFILE: 1039
Resource.SPOT_HALFTONE: 1043
Resource.JUMP_TO_XPEP: 1052
Resource.EXIF_DATA_1: 1058
Resource.EXIF_DATA_3: 1059
Resource.XMP_METADATA: 1060
Resource.CAPTION_DIGEST: 1061
Resource.ALTERNATE_DUOTONE_COLORS: 1066
Resource.ALTERNATE_SPOT_COLORS: 1067
Resource.HDR_TONING_INFO: 1070
Resource.PRINT_INFO_CS2: 1071
Resource.COLOR_SAMPLERS_RESOURCE: 1073
Resource.DISPLAY_INFO: 1077
Resource.MAC_NSPRINTINFO: 1084
Resource.WINDOWS_DEVMODE: 1085
Resource.PATH_INFO_N: 2000-2999
Resource.PLUGIN_RESOURCES_N: 4000-4999
Resource.IMAGE_READY_VARIABLES: 7000
Resource.IMAGE_READY_DATA_SETS: 7001
Resource.IMAGE_READY_DEFAULT_SELECTED_STATE: 7002
Resource.IMAGE_READY_7_ROLLOVER_EXPANDED_STATE: 7003
Resource.IMAGE_READY_ROLLOVER_EXPANDED_STATE: 7004
Resource.IMAGE_READY_SAVE_LAYER_SETTINGS: 7005
Resource.IMAGE_READY_VERSION: 7006
Resource.LIGHTROOM_WORKFLOW: 8000
ImageResources
class psd_tools.psd.image_resources.ImageResources(items=NOTHING)
Image resources section of the PSD file โ a Dict of ImageResource ๐.
get_data(key: Any, default: Any = None) -> Any
Get data from the image resources ๐ซถ.
Shortcut for the following:
if key in image_resources:
value = tagged_blocks[key].data
classmethod new(**kwargs: Any) -> T_ImageResources
Create a new default image resouces. (yes bestie, that's how it's spelled, I don't make the rules ๐)
Returns:
ImageResources
ImageResource
class psd_tools.psd.image_resources.ImageResource(signature: bytes = b'8BIM', key: int = 1000, name: str = '', data: bytes = b'')
Image resource block ๐ธ. Attributes:
signatureโ Binary signature. Usuallyb'8BIM', but some resources use alternative signatures such asb'MeSa'(e.g.,IMAGE_READY_VARIABLES <#psd_tools.constants.Resource.IMAGE_READY_VARIABLES>),b'AgHg',b'PHUT', orb'DCSR'.keyโ Unique identifier for the resource. SeeResource <#psd_tools.constants.Resource>.namedataโ The resource data.
AlphaIdentifiers
class psd_tools.psd.image_resources.AlphaIdentifiers(items=NOTHING)
List of alpha identifiers ๐.
AlphaNamesPascal
class psd_tools.psd.image_resources.AlphaNamesPascal(items=NOTHING)
List of alpha names ๐.
AlphaNamesUnicode
class psd_tools.psd.image_resources.AlphaNamesUnicode(items=NOTHING)
List of alpha names ๐. (yes, again. twins.)
Byte
class psd_tools.psd.image_resources.Byte(value=0)
Byte element ๐ฆ.
GridGuidesInfo
class psd_tools.psd.image_resources.GridGuidesInfo(version: int = 1, horizontal: int = 0, vertical: int = 0, data=NOTHING)
Grid and guides info structure โจ.
HalftoneScreens
class psd_tools.psd.image_resources.HalftoneScreens(items=NOTHING)
Halftone screens ๐.
HalftoneScreen
class psd_tools.psd.image_resources.HalftoneScreen(freq: int = 0, unit: int = 0, angle: int = 0, shape: int = 0, use_accurate: bool = False, use_printer: bool = False)
Halftone screen ๐. Attributes:
frequnitangleshapeuse_accurateuse_printer
Integer
class psd_tools.psd.image_resources.Integer(value=0)
Integer element ๐.
LayerGroupEnabledIDs
class psd_tools.psd.image_resources.LayerGroupEnabledIDs(items=NOTHING)
Layer group enabled ids โ .
LayerGroupInfo
class psd_tools.psd.image_resources.LayerGroupInfo(items=NOTHING)
Layer group info list ๐.
LayerSelectionIDs
class psd_tools.psd.image_resources.LayerSelectionIDs(items=NOTHING)
Layer selection ids โ .
ShortInteger
class psd_tools.psd.image_resources.ShortInteger(value=0)
Short integer element ๐ง.
PascalString
class psd_tools.psd.image_resources.PascalString(value: object = None)
Pascal string element ๐.
PixelAspectRatio
class psd_tools.psd.image_resources.PixelAspectRatio(value=0.0, version: int = 1)
Pixel aspect ratio ๐.
PrintFlags
class psd_tools.psd.image_resources.PrintFlags(labels: bool = False, crop_marks: bool = False, colorbars: bool = False, registration_marks: bool = False, negative: bool = False, flip: bool = False, interpolate: bool = False, caption: bool = False, print_flags: bool | None = None)
Print flags ๐จ๏ธ.
PrintFlagsInfo
class psd_tools.psd.image_resources.PrintFlagsInfo(version: int = 0, center_crop: int = 0, bleed_width_value: int = 0, bleed_width_scale: int = 0)
Print flags info structure ๐จ๏ธ. Attributes:
versioncenter_cropbleed_width_valuebleed_width_scale
PrintScale
class psd_tools.psd.image_resources.PrintScale(style=PrintScaleStyle.CENTERED, x: float = 0.0, y: float = 0.0, scale: float = 0.0)
okay so this one is literally just the print scale structure bestie, that's the whole vibe ๐
styleโ the style babexโ the xyโ the yscaleโ the scale
ResoulutionInfo
class psd_tools.psd.image_resources.ResoulutionInfo(horizontal: int = 0, horizontal_unit: int = 0, width_unit: int = 0, vertical: int = 0, vertical_unit: int = 0, height_unit: int = 0)
yes the "Resoulution" spelling is genuinely in there, I am NOT fixing it, it's canon ๐ซถ this is the resoulution info structure.
horizontalโ horizontal valuehorizontal_unitโ horizontal unitwidth_unitโ width unitverticalโ vertical valuevertical_unitโ vertical unitheight_unitโ height unit
Slices
class psd_tools.psd.image_resources.Slices(version: int = 0, data: object = None)
the slices resource, slay ๐ธ
versionโ versiondataโ data
SlicesV6
class psd_tools.psd.image_resources.SlicesV6(bbox=NOTHING, name: str = '', items=NOTHING)
slices resource but make it version 6 โจ
bboxโ bounding boxnameโ nameitemsโ the items
SliceV6
class psd_tools.psd.image_resources.SliceV6(slice_id: int = 0, group_id: int = 0, origin: int = 0, associated_id: int | None = None, name: str = '', slice_type: int = 0, bbox=NOTHING, url: str = '', target: str = '', message: str = '', alt_tag: str = '', cell_is_html: bool = False, cell_text: str = '', horizontal_align: int = 0, vertical_align: int = 0, alpha: int = 0, red: int = 0, green: int = 0, blue: int = 0, data: object = None)
the slice element for version 6, she has a LOT going on and we respect her for it ๐
slice_idโ slice idgroup_idโ group idoriginโ originassociated_idโ associated idnameโ nameslice_typeโ slice typebboxโ bounding boxurlโ urltargetโ targetmessageโ messagealt_tagโ alt tagcell_is_htmlโ cell is htmlcell_textโ cell texthorizontalโ horizontal (yep, that's what the attribute list says, even though the constructor calls ithorizontal_alignโ we do not editorialize, we simply report ๐)verticalโ vertical (same deal, constructor saysvertical_align)alphaโ alpharedโ redgreenโ greenblueโ bluedataโ data
fr fr just re-reading the signature is the whole job here bestie
ThumbnailResource
class psd_tools.psd.image_resources.ThumbnailResource(fmt: int = 0, width: int = 0, height: int = 0, row: int = 0, total_size: int = 0, bits: int = 0, planes: int = 0, data: bytes = b'')
thumbnail resource structure, iconic little picture energy ๐
fmtโ formatwidthโ widthheightโ heightrowโ rowtotal_sizeโ total sizesizeโ size (yes it's listed as an attribute but not in the constructor args, that's just how she is)bitsโ bitsplanesโ planesdataโ data
ThumbnailResourceV4
class psd_tools.psd.image_resources.ThumbnailResourceV4(fmt: int = 0, width: int = 0, height: int = 0, row: int = 0, total_size: int = 0, bits: int = 0, planes: int = 0, data: bytes = b'')
ThumbnailResource but for V4, and the original gives us literally no description text beyond the signature so that's what we're working with ๐ญ
TransferFunctions
class psd_tools.psd.image_resources.TransferFunctions(items=NOTHING)
transfer functions, plural, a whole lil collection ๐
TransferFunction
class psd_tools.psd.image_resources.TransferFunction(curve=NOTHING, override: int = 0)
transfer function for a single plate, and this one's got lore:
Contains 13 signed short integers representing curve control points in the range 0...1000 (corresponding to 0.0%...100.0%). The first and last values are always present; any intermediate value may be -1 to indicate that no control point exists at that position. A NULL (identity) transfer curve has the form:
[0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1000]
Followed by one unsigned short override flag (non-zero means the transfer function overrides the default).
See Adobe PSD spec ยงTransfer Functions <https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1071095>.
URLList
class psd_tools.psd.image_resources.URLList(items=NOTHING)
URL list structure ๐ฆ
URLItem
class psd_tools.psd.image_resources.URLItem(number: int = 0, id: int = 0, name: str = '')
one single URL item, main character of the list ngl ๐
numberโ numberidโ idnameโ name
VersionInfo
class psd_tools.psd.image_resources.VersionInfo(version: int = 1, has_composite: bool = False, writer: str = '', reader: str = '', file_version: int = 1)
version info structure, the receipts of who wrote and read this thing ๐
versionโ versionhas_compositeโ has compositewriterโ writerreaderโ readerfile_versionโ file version
psd_tools.psd.layer_and_mask
layer and mask data structures. This is where it gets real bestie ๐
This module implements the low-level binary structures for PSD layers and masks, corresponding to the "Layer and Mask Information" section of PSD files. This is one of the most complex parts of the PSD format.
Key classes:
LayerAndMaskInformation: Top-level container for all layer dataLayerInfo: Contains layer records and channel image dataLayerRecords: List of individual layer recordsLayerRecord: Single layer metadata (name, bounds, blend mode, etc.)ChannelInfo: Channel metadata within a layer recordChannelImageData: Compressed pixel data for all channelsChannelData: Single channel's compressed pixel dataMaskData: Layer mask parametersGlobalLayerMaskInfo: Document-wide mask settingsTaggedBlocks: Extended layer metadata (seepsd_tools.psd.tagged_blocks)
The layer structure in PSD files is stored as a flat list with implicit hierarchy. Group boundaries are marked by special layers with SectionDivider tagged blocks:
BOUNDING_SECTION_DIVIDER: Marks the start of a group (the layer that opens the group)OPEN_FOLDERorCLOSED_FOLDER: Marks the end of a group (the closing divider layer)OPEN_FOLDER: Group was open in Photoshop UICLOSED_FOLDER: Group was closed in Photoshop UI
The high-level API (psd_tools.api) reconstructs this into a proper tree structure with parent-child relationships.
Each layer record contains:
- Metadata: Rectangle bounds, blend mode, opacity, flags
- Channel info: List of channels (R, G, B, A, masks, etc.) with byte offsets
- Blend ranges: Advanced blending parameters
- Layer name: Pascal string (legacy, inaccurate for Unicode names)
- Tagged blocks: Extended metadata in key-value format
The channel image data section follows all layer records and contains the actual compressed pixel data for each channel, referenced by the channel info structures.
Example of reading layer metadata:
from psd_tools.psd import PSD
with open('file.psd', 'rb') as f:
psd = PSD.read(f)
layer_info = psd.layer_and_mask_information.layer_info
for record in layer_info.layer_records:
print(f"Layer: {record.name}")
print(f" Bounds: {record.top}, {record.left}, {record.bottom}, {record.right}")
print(f" Blend mode: {record.blend_mode}")
print(f" Channels: {len(record.channel_info)}")
For most use cases, prefer the high-level Layer API (psd_tools.api.layers.Layer) which provides easier access to this data.
LayerAndMaskInformation
class psd_tools.psd.layer_and_mask.LayerAndMaskInformation(layer_info: LayerInfo | None = None, global_layer_mask_info: GlobalLayerMaskInfo | None = None, tagged_blocks: TaggedBlocks | None = None)
the layer and mask information section, the big container energy ๐ฆ
layer_infoโ SeeLayerInfo.global_layer_mask_infoโ SeeGlobalLayerMaskInfo.tagged_blocksโ SeeTaggedBlocks(psd_tools.psd.tagged_blocks.TaggedBlocks).
LayerInfo
class psd_tools.psd.layer_and_mask.LayerInfo(layer_count: int = 0, layer_records: LayerRecords = NOTHING, channel_image_data: ChannelImageData = NOTHING)
high-level organization of the layer information, she's the manager fr ๐
layer_countโ Layer count. If it is a negative number, its absolute value is the number of layers and the first alpha channel contains the transparency data for the merged result.layer_recordsโ Information about each layer. SeeLayerRecords.channel_image_dataโ Channel image data. SeeChannelImageData.
GlobalLayerMaskInfo
class psd_tools.psd.layer_and_mask.GlobalLayerMaskInfo(overlay_color: list[int] | None = None, opacity: int = 0, kind=GlobalLayerMaskKind.PER_LAYER)
global mask information, document-wide and iconic ๐
overlay_colorโ Overlay color space (undocumented) and color components.opacityโ Opacity.0= transparent,100= opaque.kindโ Kind.0= Color selected--i.e. inverted;1= Color protected;128= use value stored per layer. This value is preferred. The others are for backward compatibility with beta versions.
not me clocking that 128 is the one you actually want ๐ backwards compat is giving beta
LayerRecords
class psd_tools.psd.layer_and_mask.LayerRecords(items=NOTHING)
list of layer records. See LayerRecord. Just a whole pile of them, one per layer ๐
LayerRecord
class psd_tools.psd.layer_and_mask.LayerRecord(top: int = 0, left: int = 0, bottom: int = 0, right: int = 0, channel_info: list[ChannelInfo] = NOTHING, signature: bytes = b'8BIM', blend_mode=BlendMode.NORMAL, opacity: int = 255, clipping=Clipping.BASE, flags: LayerFlags = NOTHING, mask_data: object = None, blending_ranges: LayerBlendingRanges = NOTHING, name: str = '', tagged_blocks: TaggedBlocks = NOTHING)
the layer record, aka the single most populated signature on this whole page and honestly? she ate ๐
topโ Top position.leftโ Left position.bottomโ Bottom position.rightโ Right position.channel_infoโ List ofChannelInfo.signatureโ Blend mode signatureb'8BIM'.blend_modeโ Blend mode key. SeeBlendMode(psd_tools.constants.BlendMode).opacityโ Opacity,0= transparent,255= opaque.clippingโ Clipping,0= base,1= non-base. SeeClipping(psd_tools.constants.Clipping).flagsโ SeeLayerFlags.mask_dataโMaskDataorNone.blending_rangesโ SeeLayerBlendingRanges.nameโ Layer name.tagged_blocksโ SeeTaggedBlocks(psd_tools.psd.tagged_blocks.TaggedBlocks).- property
channel_sizes:list[tuple[int, int]]โ[(width, height)].- Type:
List(psd_tools.psd.descriptor.List) of channel sizes
- Type:
- property
height:intโ Height of the layer. - property
width:intโ Width of the layer.
lowkey obsessed with how the height and width are properties whiletop/left/bottom/rightare just vibing in the constructor, but that's her design choice and we support it ๐
๐
LayerFlags
class psd_tools.psd.layer_and_mask.LayerFlags(transparency_protected: bool = False, visible: bool = True, obsolete: bool = False, photoshop_v5_later: bool = True, pixel_data_irrelevant: bool = False, undocumented_1: bool = False, undocumented_2: bool = False, undocumented_3: bool = False)
ok so this is layer flags, that's the whole vibe โจ
bestie. listen. there are undocumented flags here. maybe photoshop version, maybe a secret third thing, nobody's saying ๐ซฃ
transparency_protectedvisiblepixel_data_irrelevant
๐ LayerBlendingRanges
class psd_tools.psd.layer_and_mask.LayerBlendingRanges(composite_ranges: list[tuple[int, int]] = NOTHING, channel_ranges: list[list[tuple[int, int]]] = NOTHING)
layer blending ranges, and here's the lil rule that lives here, no cap:
all ranges contain 2 black values followed by 2 white values ๐ค๐ค๐ค๐ค
composite_rangesโ list of composite gray blend source and destination ranges.channel_rangesโ list of channel source and destination ranges.
๐ MaskData
class psd_tools.psd.layer_and_mask.MaskData(top: int = 0, left: int = 0, bottom: int = 0, right: int = 0, background_color: int = 0, flags: MaskFlags = NOTHING, parameters: MaskParameters | None = None, real_flags: MaskFlags | None = None, real_background_color: int | None = None, real_top: int | None = None, real_left: int | None = None, real_bottom: int | None = None, real_right: int | None = None)
mask data โจ and the lore here is that the real user mask is the final composite mask of vector and pixel masks. iconic behaviour fr fr.
topโ top position.leftโ left position.bottomโ bottom position.rightโ right position.background_colorโ default color.0or255.flagsโ seeMaskFlags.parametersโMaskParametersorNone.real_flagsโ real user mask flags. seeMaskFlags.real_background_colorโ real user mask background.0or255.real_topโ top position of real user mask.real_leftโ left position of real user mask.real_bottomโ bottom position of real user mask.real_rightโ right position of real user mask.
and then the properties, which are giving computed, not stored energy:
- property
height: intโ height of the mask. - property
real_height: intโ height of real user mask. - property
real_width: intโ width of real user mask. - property
width: intโ width of the mask.
๐ฆ MaskFlags
class psd_tools.psd.layer_and_mask.MaskFlags(pos_relative_to_layer: bool = False, mask_disabled: bool = False, invert_mask: bool = False, user_mask_from_render: bool = False, parameters_applied: bool = False, undocumented_1: bool = False, undocumented_2: bool = False, undocumented_3: bool = False)
mask flags ๐
pos_relative_to_layerโ position relative to layer.mask_disabledโ layer mask disabled.invert_maskโ invert layer mask when blending (obsolete, so like, old news ๐).user_mask_from_renderโ the user mask actually came from rendering other data.parameters_appliedโ the user and/or vector masks have parameters applied to them.
๐ MaskParameters
class psd_tools.psd.layer_and_mask.MaskParameters(user_mask_density: int | None = None, user_mask_feather: float | None = None, vector_mask_density: int | None = None, vector_mask_feather: float | None = None)
mask parameters, four lil guys, no descriptions attached, they just vibe:
user_mask_densityuser_mask_feathervector_mask_densityvector_mask_feather
๐ ChannelInfo
class psd_tools.psd.layer_and_mask.ChannelInfo(id=ChannelID.CHANNEL_0, length: int = 0)
channel information ๐ธ
idโ channel ID:0= red,1= green, etc.;-1= transparency mask;-2= user supplied layer mask,-3real user supplied layer mask (when both a user mask and a vector mask are present). SeeChannelID.lengthโ length of the corresponding channel data.
๐ ChannelImageData
class psd_tools.psd.layer_and_mask.ChannelImageData(items=NOTHING)
list of channel data list โจ
the size of this list corresponds to the size of LayerRecords. each item corresponds to the channels of each layer.
See ChannelDataList.
๐ง ChannelDataList
class psd_tools.psd.layer_and_mask.ChannelDataList(items=NOTHING)
list of channel image data, corresponding to each color or alpha ๐ซ
See ChannelData.
๐ ChannelData
class psd_tools.psd.layer_and_mask.ChannelData(compression=Compression.RAW, data: bytes = b'')
channel data ๐ฉท
compressionโ compression type. SeeCompression.dataโ data.get_data(width: int, height: int, depth: int, version: int = 1) -> bytesโ get decompressed channel data.
Parameters:
- width โ width.
- height โ height.
- depth โ bit depth of the pixel.
- version โ psd file version.
Return type: bytes
set_data(data: bytes, width: int, height: int, depth: int, version: int = 1) -> intโ set raw channel data and compress to store.
Parameters:
- data โ raw data bytes to write.
- compression โ compression type, see
Compression. - width โ width.
- height โ height.
- depth โ bit depth of the pixel.
- version โ psd file version.
๐ซ psd_tools.psd.linked_layer
linked layer structure ๐ซถ
๐ธ LinkedLayers
class psd_tools.psd.linked_layer.LinkedLayers(items=NOTHING)
list of LinkedLayer structure. See LinkedLayer.
๐ฅ LinkedLayer
class psd_tools.psd.linked_layer.LinkedLayer(kind: LinkedLayerType = LinkedLayerType.ALIAS, version: int = 1, uuid: str = '', filename: str = '', filetype: bytes = b'\x00\x00\x00\x00', creator: bytes = b'\x00\x00\x00\x00', filesize: int | None = None, open_file: DescriptorBlock | None = None, linked_file: DescriptorBlock | None = None, timestamp: tuple | None = None, data: bytes | None = None, child_id: str | None = None, mod_time: float | None = None, lock_state: int | None = None)
LinkedLayer structure ๐
the fields are just... listed. seventeen of them. we don't gatekeep:
kindversionuuidfilenamefiletypecreatorfilesizeopen_filelinked_filetimestampdatachild_idmod_timelock_state
๐ psd_tools.psd.patterns
patterns structure ๐ฆ
๐ Patterns
class psd_tools.psd.patterns.Patterns(items=NOTHING)
list of Pattern structure. See Pattern.
โจ Pattern
class psd_tools.psd.patterns.Pattern(version: int = 1, image_mode=ColorMode.RGB, point: tuple[int, int] = (0, 0), name: str = '', pattern_id: str = '', color_table: list[tuple[int, int, int]] = NOTHING, data: VirtualMemoryArrayList = None)
Pattern structure ๐
versionimage_modeโ seeColorModepointโ size in tuple.nameโstrname of the pattern.pattern_idโ ID of this pattern.color_tableโ color table if the mode isINDEXED.dataโ seeVirtualMemoryArrayList
๐ซง VirtualMemoryArrayList
class psd_tools.psd.patterns.VirtualMemoryArrayList(version: int = 3, rectangle: tuple[int, int, int, int] = (0, 0, 0, 0), channels: list[VirtualMemoryArray] = NOTHING)
VirtualMemoryArrayList structure. container of channels ๐งบ
versionrectangleโ tuple ofintchannelsโ list ofVirtualMemoryArray
๐ VirtualMemoryArray
class psd_tools.psd.patterns.VirtualMemoryArray(is_written: int = 0, depth: int | None = None, rectangle: tuple[int, int, int, int] | None = None, pixel_depth: int | None = None, compression=Compression.RAW, data: bytes = b'')
VirtualMemoryArrayList structure, corresponding to each channel โจ
is_writtendepthrectanglepixel_depthcompressiondataget_data() -> bytes | Noneโ get decompressed bytes.set_data(size: tuple[int, int], data: bytes, depth: int, compression: int = 0) -> Noneโ set bytes.
๐ psd_tools.psd.tagged_blocks
tagged block data structure ๐ท๏ธ
๐ Todo
support the following tagged blocks: Tag.PATTERN_DATA, Tag.TYPE_TOOL_INFO, Tag.LAYER, Tag.ALPHA
fr fr this is a to-do list, meaning those ones are not supported yet. don't come for me, come for the codebase ๐
๐
TaggedBlocks
class psd_tools.psd.tagged_blocks.TaggedBlocks(items=NOTHING)
dict of tagged block items ๐
see Tag for available keys.
Example:
from psd_tools.constants import Tag
# Iterate over fields
for key in tagged_blocks:
print(key)
# Get a field
value = tagged_blocks.get_data(Tag.TYPE_TOOL_OBJECT_SETTING)
๐ฆ TaggedBlock
class psd_tools.psd.tagged_blocks.TaggedBlock(signature: bytes = b'8BIM', key: bytes = b'', data: bytes = b'')
layer tagged block with extra info ๐
keyโ 4-character code. SeeTagdataโ data.
๐ Annotations
class psd_tools.psd.tagged_blocks.Annotations(items=NOTHING, major_version: int = 2, minor_version: int = 1)
list of Annotation, see :py:class: .Annotation ๐
major_versionminor_version
๐ธ Annotation
class psd_tools.psd.tagged_blocks.Annotation(kind: bytes = b'txtA', is_open: int = 0, flags: int = 0, optional_blocks: int = 1, icon_location=NOTHING, popup_location=NOTHING, color: Color = NOTHING, author: str = '', name: str = '', mod_date: str = '', marker: bytes = b'txtC', data: bytes = b'')
Annotation structure โจ
kindis_open
๐ง Bytes
class psd_tools.psd.tagged_blocks.Bytes(value: bytes = b'\x00\x00\x00\x00')
Bytes structure ๐ซ
value
ChannelBlendingRestrictionsSetting
class psd_tools.psd.tagged_blocks.ChannelBlendingRestrictionsSetting(items=NOTHING)
okay so this is the ChannelBlendingRestrictionsSetting structure, and she's honestly so low-maintenance ๐
literally just a list of restricted channel numbers (int). that's the whole thing. no notes.
FilterMask
class psd_tools.psd.tagged_blocks.FilterMask(color: Color = NOTHING, opacity: int = 0)
The FilterMask structure โจ and she's serving exactly two fields:
colorโ the color, bestie ๐opacityโ the opacity
MetadataSettings
class psd_tools.psd.tagged_blocks.MetadataSettings(items=NOTHING)
The MetadataSettings structure. that's the vibe, that's the entry ๐ฆ
MetadataSetting
class psd_tools.psd.tagged_blocks.MetadataSetting(signature: bytes = b'8BIM', key: bytes = b'', copy_on_sheet: bool = False, data: bytes = b'')
The MetadataSetting structure ๐
PixelSourceData2
class psd_tools.psd.tagged_blocks.PixelSourceData2(items=NOTHING)
The PixelSourceData2 structure. iconic, brief, no crumbs ๐ธ
PlacedLayerData
class psd_tools.psd.tagged_blocks.PlacedLayerData(kind: bytes = b'plcL', version: int = 3, uuid: bytes = b'', page: int = 0, total_pages: int = 0, anti_alias: int = 0, layer_type=PlacedLayerType.UNKNOWN, transform: tuple = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), warp: object = None)
The PlacedLayerData structure ๐ she's got the whole ensemble cast in her signature, look at her go.
ProtectedSetting
class psd_tools.psd.tagged_blocks.ProtectedSetting(value=0)
The ProtectedSetting structure. short. sweet. protected. ๐ซถ
ReferencePoint
class psd_tools.psd.tagged_blocks.ReferencePoint(items=NOTHING)
The ReferencePoint structure โจ
SectionDividerSetting
class psd_tools.psd.tagged_blocks.SectionDividerSetting(kind=SectionDivider.OTHER, signature: bytes | None = None, blend_mode: BlendMode <#psd_tools.constants.BlendMode> | None = None, sub_type: int | None = None)
The SectionDividerSetting structure, and her documented bits are:
kindโ what kind of divider she isblend_modeโ the blend modesub_typeโ the sub type
SheetColorSetting
class psd_tools.psd.tagged_blocks.SheetColorSetting(value=SheetColorType.NO_COLOR)
SheetColorSetting value ๐
This setting represents color label in the layers panel in Photoshop UI.
so like, the lil colored tag on your layer, bestie. that's her.
valueโ the value
SmartObjectLayerData
class psd_tools.psd.tagged_blocks.SmartObjectLayerData(kind: bytes = b'soLD', version: int = 5, data: DescriptorBlock = NOTHING)
funnily enough the docstring here calls her a VersionedDescriptorBlock structure, and we are NOT arguing with the source, periodt. her fields:
kindโ the kindversionโ the versiondataโ the data
TypeToolObjectSetting
class psd_tools.psd.tagged_blocks.TypeToolObjectSetting(version: int = 1, transform: tuple = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0), text_version: int = 1, text_data: DescriptorBlock = NOTHING, warp_version: int = 1, warp: DescriptorBlock = NOTHING, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0)
The TypeToolObjectSetting structure, aka the text layer girlies' main character moment ๐
versionโ the versiontransformโ Tuple of affine transform parameters (xx, xy, yx, yy, tx, ty).text_versionโ the text versiontext_dataโ the text datawarp_versionโ the warp versionwarpโ the warpleftโ the lefttopโ the toprightโ the rightbottomโ the bottom
UserMask
class psd_tools.psd.tagged_blocks.UserMask(color: Color = NOTHING, opacity: int = 0, flag: int = 128)
The UserMask structure ๐
colorโ the coloropacityโ the opacityflagโ the flag (and yes, she defaults to128)
psd_tools.psd.vector
Vector mask, path, and stroke structure. that's the whole summary and honestly? slay ๐
Path
class psd_tools.psd.vector.Path(items=NOTHING)
List-like Path structure. Elements are either PathFillRule, InitialFillRule, ClipboardRecord, ClosedPath, or OpenPath.
Subpath
class psd_tools.psd.vector.Subpath(items=NOTHING, operation: int = 1, unknown1: int = 1, unknown2: int = 0, index: int = 0, unknown3: bytes = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
Subpath element. This is a list of Knot objects.
Note: There are undocumented data associated with this structure.
okay bestie, listen, the mystery is part of her charm ๐
operationโintvalue indicating how multiple subpath should be combined:1: Or (union)2: Not-Or3: And (intersect)0: Xor (exclude)
The first path element is applied to the background surface. Intersection does not have strokes.
indexโintindex that specifies corresponding origination object.is_closed() -> boolโ Returns whether if the path is closed or not.- Returns:
bool.
- Returns:
Knot
class psd_tools.psd.vector.Knot(preceding: tuple = (0.0,), anchor: tuple = (0.0,), leaving: tuple = (0.0,))
Knot element consisting of 3 control points for Bezier curves ๐ฆ the trio, if you will:
precedingโ(y, x)tuple of preceding control point in relative coordinates.anchorโ(y, x)tuple of anchor point in relative coordinates.leavingโ(y, x)tuple of leaving control point in relative coordinates.
ClipboardRecord
class psd_tools.psd.vector.ClipboardRecord(top: int = 0, left: int = 0, bottom: int = 0, right: int = 0, resolution: int = 0)
Clipboard record โจ
topโ Top position inintleftโ Left position inintbottomโ Bottom position inintrightโ Right position inintresolutionโ Resolution inint
PathFillRule
class psd_tools.psd.vector.PathFillRule
Path fill rule record, empty. she said "no data, only vibes" ๐
InitialFillRule
class psd_tools.psd.vector.InitialFillRule(value=0)
Initial fill rule record.
ruleโ A value of1means that the fill starts with all pixels. The value will be either0or1.
VectorMaskSetting
class psd_tools.psd.vector.VectorMaskSetting(version: int = 3, flags: int = 0, path: Path <#psd_tools.psd.vector.Path> | None = None)
The VectorMaskSetting structure:
versionโ the versionpathโ List ofSubpathobjects.- property
disable: boolโ Flag to indicate that the vector mask is disabled. - property
invert: boolโ Flag to indicate that the vector mask is inverted. - property
not_link: boolโ Flag to indicate that the vector mask is not linked.
VectorStrokeContentSetting
class psd_tools.psd.vector.VectorStrokeContentSetting(items=NOTHING, name: str = '', classID: bytes = b'null', key: bytes = b'\x00\x00\x00\x00', version: int = 1)
Dict-like Descriptor-based structure. See Descriptor <#psd_tools.psd.descriptor.Descriptor>.
keyโ the keyversionโ the version
psd_tools.terminology
Constants for descriptor.
This file is automaticaly generated by tools/extract_terminology.py โ yes, that spelling is in the source, we keep it, we don't touch it ๐ซถ
Klass
class psd_tools.terminology.Klass(*values)
Klass definitions extracted from PITerminology.h.
See https://www.adobe.com/devnet/photoshop/sdk.html
now then. the big one. the full roster. every single one, no skipping, no cap ๐
Action = b'Actn'ActionSet = b'ASet'Adjustment = b'Adjs'AdjustmentLayer = b'AdjL'AirbrushTool = b'AbTl'AlphaChannelOptions = b'AChl'AntiAliasedPICTAcquire = b'AntA'Application = b'capp'Arrowhead = b'cArw'ArtHistoryBrushTool = b'ABTl'Assert = b'Asrt'AssumedProfile = b'AssP'BMPFormat = b'BMPF'BackLight = b'BakL'BackgroundEraserTool = b'SETl'BackgroundLayer = b'BckL'BevelEmboss = b'ebbl'BitmapMode = b'BtmM'BlendRange = b'Blnd'BlurTool = b'BlTl'BookColor = b'BkCl'BrightnessContrast = b'BrgC'Brush = b'Brsh'BurnInTool = b'BrTl'CMYKColor = b'CMYC'CMYKColorMode = b'CMYM'CMYKSetup = b'CMYS'CachePrefs = b'CchP'Calculation = b'Clcl'Channel = b'Chnl'ChannelMatrix = b'ChMx'ChannelMixer = b'ChnM'ChromeFX = b'ChFX'CineonFormat = b'SDPX'ClippingInfo = b'Clpo'ClippingPath = b'ClpP'CloneStampTool = b'ClTl'Color = b'Clr 'ColorBalance = b'ClrB'ColorCast = b'ColC'ColorCorrection = b'ClrC'ColorPickerPrefs = b'Clrk'ColorSampler = b'ClSm'ColorStop = b'Clrt'Command = b'Cmnd'Contour = b'FxSc'CurvePoint = b'CrPt'Curves = b'Crvs'CurvesAdjustment = b'CrvA'CustomPalette = b'Cstl'CustomPhosphors = b'CstP'CustomWhitePoint = b'CstW'DicomFormat = b'Dicm'DisplayPrefs = b'DspP'Document = b'Dcmn'DodgeTool = b'DdTl'DropShadow = b'DrSh'DuotoneInk = b'DtnI'DuotoneMode = b'DtnM'EPSGenericFormat = b'EPSG'EPSPICTPreview = b'EPSC'EPSTIFFPreview = b'EPST'EXRf = b'EXRf'Element = b'Elmn'Ellipse = b'Elps'EraserTool = b'ErTl'Export = b'Expr'FileInfo = b'FlIn'FileSavePrefs = b'FlSv'FillFlash = b'FilF'FlashPixFormat = b'FlsP'FontDesignAxes = b'FntD'Format = b'Fmt 'FrameFX = b'FrFX'GIF89aExport = b'GF89'GIFFormat = b'GFFr'GeneralPrefs = b'GnrP'GlobalAngle = b'gblA'Gradient = b'Grdn'GradientFill = b'Grdf'GradientMap = b'GdMp'GradientTool = b'GrTl'GraySetup = b'GrSt'Grayscale = b'Grsc'GrayscaleMode = b'Grys'Guide = b'Gd 'GuidesPrefs = b'GdPr'HSBColor = b'HSBC'HSBColorMode = b'HSBM'HalftoneScreen = b'HlfS'HalftoneSpec = b'Hlfp'HistoryBrushTool = b'HBTl'HistoryPrefs = b'CHsP'HistoryState = b'HstS'HueSatAdjustment = b'HStA'HueSatAdjustmentV2 = b'Hst2'HueSaturation = b'HStr'IFFFormat = b'IFFF'IllustratorPathsExport = b'IlsP'ImagePoint = b'ImgP'Import = b'Impr'IndexedColorMode = b'IndC'InkTransfer = b'InkT'InnerGlow = b'IrGl'InnerShadow = b'IrSh'InterfaceColor = b'IClr'Invert = b'Invr'JPEGFormat = b'JPEG'LabColor = b'LbCl'LabColorMode = b'LbCM'Layer = b'Lyr 'LayerEffects = b'Lefx'LayerFXVisible = b'lfxv'Levels = b'Lvls'LevelsAdjustment = b'LvlA'LightSource = b'LghS'Line = b'Ln 'MacPaintFormat = b'McPn'MagicEraserTool = b'MgEr'MagicPoint = b'Mgcp'Mask = b'Msk 'MenuItem = b'Mn 'Mode = b'Md '
heads up bestie: some of these four-byte codes end in a literal space (looking at youb'Clr ',b'Fmt ',b'Gd ',b'Lyr ',b'Ln ',b'Msk ',b'Mn 'andb'Md ') so don't go trimming anything, fr fr ๐ฅ
and the roster keeps goingโฆ more of the alphabet is coming up next ๐
...and we just keep going, bestie, the code table does not stop and honestly? respect ๐ every one of these is an exact four-character code, casing and spaces included. Do not "tidy" them. Do not lowercase them. The trailing spaces are real and they are staying ๐ซถ
MultichannelModeโb'MltC'Nullโb'null'ObsoleteTextLayerโb'TxLy'Offsetโb'Ofst'Opacityโb'Opac'OuterGlowโb'OrGl'PDFGenericFormatโb'PDFG'PICTFileFormatโb'PICF'PICTResourceFormatโb'PICR'PNGFormatโb'PNGF'PageSetupโb'PgSt'PaintbrushToolโb'PbTl'Pathโb'Path'PathComponentโb'PaCm'PathPointโb'Pthp'Patternโb'PttR'PatternStampToolโb'PaTl'PencilToolโb'PcTl'Photoshop20Formatโb'Pht2'Photoshop35Formatโb'Pht3'PhotoshopDCS2Formatโb'PhD2'PhotoshopDCSFormatโb'PhD1'PhotoshopEPSFormatโb'PhtE'PhotoshopPDFFormatโb'PhtP'Pixelโb'Pxel'PixelPaintFormatโb'PxlP'PluginPrefsโb'PlgP'Pointโb'Pnt 'Point16โb'Pnt1'Polygonโb'Plgn'Posterizeโb'Pstr'Preferencesโb'GnrP'ProfileSetupโb'PrfS'Propertyโb'Prpr'RGBColorโb'RGBC'RGBColorModeโb'RGBM'RGBSetupโb'RGBt'Rangeโb'Rang'RawFormatโb'Rw 'Rect16โb'Rct1'Rectangleโb'Rctn'SaturationToolโb'SrTl'ScitexCTFormatโb'Sctx'Selectionโb'csel'SelectiveColorโb'SlcC'ShapingCurveโb'ShpC'SharpenToolโb'ShTl'SingleColumnโb'Sngc'SingleRowโb'Sngr'SmudgeToolโb'SmTl'Snapshotโb'SnpS'SolidFillโb'SoFi'SpotColorChannelโb'SCch'Styleโb'StyC'SubPathโb'Sbpl'TIFFFormatโb'TIFF'TargaFormatโb'TrgF'TextLayerโb'TxLr'TextStyleโb'TxtS'TextStyleRangeโb'Txtt'Thresholdโb'Thrs'Toolโb'Tool'TransferPointโb'DtnP'TransferSpecโb'Trfp'TransparencyPrefsโb'TrnP'TransparencyStopโb'TrnS'UnitsPrefsโb'UntP'UnspecifiedColorโb'UnsC'Versionโb'Vrsn'WebdavPrefsโb'Wdbv'XYYColorโb'XYYC'
โจ Enum โจ
class psd_tools.terminology.Enum(*values)
Enum definitions extracted from PITerminology.h.
See https://www.adobe.com/devnet/photoshop/sdk.html
Okay so THIS is the big one, and when I say big I mean big. One *values star-args situation and a whole alphabet of constants falling out of it. Every single one below is exact โ same letters, same caps, same any-weird-case Adobe decided on that day. Do not touch. Do not "clean up" ๐
Aโb'A 'ADSBottomsโb'AdBt'ADSCentersHโb'AdCH'ADSCentersVโb'AdCV'ADSHorizontalโb'AdHr'ADSLeftsโb'AdLf'ADSRightsโb'AdRg'ADSTopsโb'AdTp'ADSVerticalโb'AdVr'ASCIIโb'ASCI'AboutAppโb'AbAp'AbsColorimetricโb'AClr'Absoluteโb'Absl'ActualPixelsโb'ActP'Adaptiveโb'Adpt'Addโb'Add 'AdjustmentOptionsโb'AdjO'AdobeRGB1998โb'SMPT'AirbrushEraserโb'Arbs'Allโb'Al 'Amigaโb'Amga'AmountHighโb'amHi'AmountLowโb'amLo'AmountMediumโb'amMd'Angleโb'Angl'AntiAliasCrispโb'AnCr'AntiAliasHighโb'AnHi'AntiAliasLowโb'AnLo'AntiAliasMediumโb'AnMd'AntiAliasNoneโb'Anno'AntiAliasSmoothโb'AnSm'AntiAliasStrongโb'AnSt'Anyโb'Any 'AppleRGBโb'AppR'ApplyImageโb'AplI'AroundCenterโb'ArnC'Arrangeโb'Arng'Askโb'Ask 'AskWhenOpeningโb'AskW'
See how AdobeRGB1998 maps to b'SMPT'? Not intuitive, not your business, just type it right ๐
Bโb'B 'Backโb'Back'Backgroundโb'Bckg'BackgroundColorโb'BckC'Backwardโb'Bckw'Behindโb'Bhnd'Bestโb'Bst 'Betterโb'Dthb'Bicubicโb'Bcbc'Bilinearโb'Blnr'Binaryโb'Bnry'BitDepth1โb'BD1 'BitDepth16โb'BD16'BitDepth24โb'BD24'BitDepth32โb'BD32'BitDepth4โb'BD4 'BitDepth8โb'BD8 'BitDepthA1R5G5B5โb'1565'BitDepthA4R4G4B4โb'4444'BitDepthR5G6B5โb'x565'BitDepthX4R4G4B4โb'x444'BitDepthX8R8G8B8โb'x888'Bitmapโb'Btmp'Blackโb'Blck'BlackAndWhiteโb'BanW'BlackBodyโb'BlcB'Blacksโb'Blks'Blastโb'Blst'BlockEraserโb'Blk 'Blocksโb'Blks'Blueโb'Bl 'Bluesโb'Bls 'Bottomโb'Bttm'BrushDarkRoughโb'BrDR'BrushLightRoughโb'BrsL'BrushSimpleโb'BrSm'BrushSizeโb'BrsS'BrushSparkleโb'BrSp'BrushWideBlurryโb'BrbW'BrushWideSharpโb'BrsW'BrushesAppendโb'BrsA'BrushesDefineโb'BrsD'BrushesDeleteโb'Brsf'BrushesLoadโb'Brsd'BrushesNewโb'BrsN'BrushesOptionsโb'BrsO'BrushesResetโb'BrsR'BrushesSaveโb'Brsv'Builtinโb'Bltn'BurnInHโb'BrnH'BurnInMโb'BrnM'BurnInSโb'BrnS'ButtonModeโb'BtnM'
Also quick heads up ๐ โ Blks shows up twice in this list (Blacks and Blocks). That's not me being chaotic, that's just how it is. Write it exactly like that.
CIERGBโb'CRGB'CMYKโb'CMYK'CMYK64โb'CMSF'CMYKColorโb'ECMY'Calculationsโb'Clcl'Cascadeโb'Cscd'Centerโb'Cntr'CenterGlowโb'SrcC'CenteredFrameโb'CtrF'ChannelOptionsโb'ChnO'ChannelsPaletteOptionsโb'ChnP'CheckerboardLargeโb'ChcL'CheckerboardMediumโb'ChcM'CheckerboardNoneโb'ChcN'CheckerboardSmallโb'ChcS'Clearโb'Clar'ClearGuidesโb'ClrG'Clipboardโb'Clpb'ClippingPathโb'ClpP'CloseAllโb'ClsA'CoarseDotsโb'CrsD'Colorโb'Clr 'ColorBurnโb'CBrn'ColorDodgeโb'CDdg'ColorMatchโb'ClMt'ColorNoiseโb'ClNs'Colorimetricโb'Clrm'Compositeโb'Cmps'ContourCustomโb'sp06'ContourDoubleโb'sp04'ContourGaussianโb'sp02'ContourLinearโb'sp01'ContourSingleโb'sp03'ContourTripleโb'sp05'ConvertToCMYKโb'CnvC'ConvertToGrayโb'CnvG'ConvertToLabโb'CnvL'ConvertToRGBโb'CnvR'CreateDuplicateโb'CrtD'CreateInterpolationโb'CrtI'Crossโb'Crs 'CurrentLayerโb'CrrL'Customโb'Cst 'CustomPatternโb'Cstm'CustomStopsโb'CstS'Cyanโb'Cyn 'Cyansโb'Cyns'
The Contour* squad all lowercase sp and numbered out of order โ sp01, sp02, sp03, sp04, sp05, sp06 โ iconic behavior honestly ๐ฅ
Darkโb'Drk 'Darkenโb'Drkn'DarkenOnlyโb'DrkO'DashedLinesโb'DshL'Desaturateโb'Dstt'Diamondโb'Dmnd'Differenceโb'Dfrn'Diffusionโb'Dfsn'DiffusionDitherโb'DfnD'DisplayCursorsPreferencesโb'DspC'Dissolveโb'Dslv'Distortโb'Dstr'DodgeHโb'DdgH'DodgeMโb'DdgM'DodgeSโb'DdgS'Dotsโb'Dts 'Draftโb'Drft'Duotoneโb'Dtn 'EBUITUโb'EBT 'EdgeGlowโb'SrcE'EliminateEvenFieldsโb'ElmE'EliminateOddFieldsโb'ElmO'Ellipseโb'Elps'Embossโb'Embs'Exactโb'Exct'Exclusionโb'Xclu'FPXCompressLossyJPEGโb'FxJP'FPXCompressNoneโb'FxNo'Fasterโb'Dthf'Fileโb'Fle 'FileInfoโb'FlIn'FillBackโb'FlBc'FillForeโb'FlFr'FillInverseโb'FlIn'FillSameโb'FlSm'FineDotsโb'FnDt'Firstโb'Frst'FirstIdleโb'FrId'FitOnScreenโb'FtOn'ForegroundColorโb'FrgC'Forwardโb'Frwr'FreeTransformโb'FrTr'Frontโb'Frnt'FullDocumentโb'FllD'FullSizeโb'FlSz'GIFColorFileColorTableโb'GFCT'GIFColorFileColorsโb'GFCF'GIFColorFileMicrosoftPaletteโb'GFMS'GIFPaletteAdaptiveโb'GFPA'GIFPaletteExactโb'GFPE'GIFPaletteOtherโb'GFPO'GIFPaletteSystemโb'GFPS'GIFRequiredColorSpaceIndexedโb'GFCI'GIFRequiredColorSpaceRGBโb'GFRG'GIFRowOrderInterlacedโb'GFIN'GIFRowOrderNormalโb'GFNI'GaussianDistributionโb'Gsn 'GeneralPreferencesโb'GnrP'Goodโb'Gd 'GradientFillโb'GrFl'GrainClumpedโb'GrnC'GrainContrastyโb'GrCn'GrainEnlargedโb'GrnE'GrainHorizontalโb'GrnH'GrainRegularโb'GrnR'GrainSoftโb'GrSf'GrainSpeckleโb'GrSp'GrainSprinklesโb'GrSr'GrainStippledโb'GrSt'GrainVerticalโb'GrnV'GrainyDotsโb'GrnD'Graphicsโb'Grp 'Grayโb'Gry 'Gray16โb'GryX'Gray18โb'Gr18'Gray22โb'Gr22'Gray50โb'Gr50'GrayScaleโb'Gryc'Grayscaleโb'Grys'Greenโb'Grn 'Greensโb'Grns'GuidesGridPreferencesโb'GudG'HDTVโb'HDTV'HSBColorโb'HSBl'HSLColorโb'HSLC'HalftoneFileโb'HlfF'HalftoneScreenโb'HlfS'HardLightโb'HrdL'Heavyโb'Hvy 'HideAllโb'HdAl'HideSelectionโb'HdSl'Highโb'High'HighQualityโb'Hgh 'Highlightsโb'Hghl'Histogramโb'Hstg'Historyโb'Hsty'HistoryPaletteOptionsโb'HstO'HistoryPreferencesโb'HstP'Horizontalโb'Hrzn'HorizontalOnlyโb'HrzO'Hueโb'H 'IBMPCโb'IBMP'ICCโb'ICC 'Iconโb'Icn 'IdleVMโb'IdVM'Ignoreโb'Ignr'Imageโb'Img 'ImageCachePreferencesโb'ImgP'IndexedColorโb'Indl'InfoPaletteOptionsโb'InfP'InfoPaletteToggleSamplersโb'InfT'InnerBevelโb'InrB'InsetFrameโb'InsF'
High is literally just b'High' โ no truncation, no four-char squeeze, just vibes โจ and it's still correct, so leave it alone.
okay bestie, we're still in the constant corridor and it is long but also lowkey mesmerizing ๐ no cap, every one of these is exact, so don't let the vibes fool you:
Insideโb'Insd'โจJPEGโb'JPEG'๐ธJustifyAllโb'JstA'๐JustifyFullโb'JstF'๐KeepProfileโb'KPro'๐KeyboardPreferencesโb'KybP'โจ๏ธLabโb'Lab '๐งชLab48โb'LbCF'๐ฌLabColorโb'LbCl'๐จLargeโb'Lrg '๐Lastโb'Lst 'โฎ๏ธLastFilterโb'LstF'๐LayerOptionsโb'LyrO'๐งLayersPaletteOptionsโb'LyrP'๐๏ธLeftโb'Left'โฌ ๏ธLeft_PLUGINโb'Lft '๐งฉLevelBasedโb'LvlB'๐Lightโb'Lgt '๐กLightBlueโb'LgtB'๐ฉตLightDirBottomโb'LDBt'โฌ๏ธLightDirBottomLeftโb'LDBL'โ๏ธLightDirBottomRightโb'LDBR'โ๏ธLightDirLeftโb'LDLf'โฌ ๏ธLightDirRightโb'LDRg'โก๏ธLightDirTopโb'LDTp'โฌ๏ธLightDirTopLeftโb'LDTL'โ๏ธLightDirTopRightโb'LDTR'โ๏ธLightDirectionalโb'LghD'๐ฆLightGrayโb'LgtG'๐ฉถLightOmniโb'LghO'๐LightPosBottomโb'LPBt'๐LightPosBottomLeftโb'LPBL'๐LightPosBottomRightโb'LPBr'๐LightPosLeftโb'LPLf'๐LightPosRightโb'LPRg'๐LightPosTopโb'LPTp'๐LightPosTopLeftโb'LPTL'๐LightPosTopRightโb'LPTR'๐LightRedโb'LgtR'๐ฉธLightSpotโb'LghS'๐Lightenโb'Lghn'๐LightenOnlyโb'LghO'๐Lightnessโb'Lght'๐ชถLineโb'Ln '๐Linearโb'Lnr '๐Linesโb'Lns 'ใฐ๏ธLinkedโb'Lnkd'๐LongLinesโb'LngL'๐LongStrokesโb'LngS'๐๏ธLowโb'Low '๐ฝLowQualityโb'Lw '๐ซLowerโb'Lwr '๐ปLuminosityโb'Lmns'โจMacThumbnailโb'McTh'๐Macintoshโb'Mcnt'๐ฅ๏ธMacintoshSystemโb'McnS'๐Magentaโb'Mgnt'๐Magentasโb'Mgnt'๐Maskโb'Msk '๐ญMaskedAreasโb'MskA'๐ซฅMasterAdaptiveโb'MAdp'๐งMasterPerceptualโb'MPer'๐๏ธMasterSelectiveโb'MSel'๐ฏMaximumโb'Mxmm'๐MaximumQualityโb'Mxm '๐Mayaโb'Maya'๐บMediumโb'Mdim'โ๏ธMediumBlueโb'MdmB'๐ตMediumDotsโb'MdmD'๐MediumLinesโb'MdmL'๐MediumQualityโb'Mdm '๐๏ธMediumStrokesโb'MdmS'๐๏ธMemoryPreferencesโb'MmrP'๐พMergeChannelsโb'MrgC'๐งฌMergedโb'Mrgd'๐MergedLayersโb'Mrg2'๐งMergedLayersOldโb'MrgL'๐งMiddleโb'Mddl'๐ฏMidtonesโb'Mdtn'๐ModeGrayโb'MdGr'โซModeRGBโb'MdRG'๐Monitorโb'Moni'๐ฅ๏ธMonitorSetupโb'MntS'โ๏ธMonotoneโb'Mntn'๐ตMulti72Colorโb'72CM'๐Multi72Grayโb'72GM'๐ซ๏ธMultiNoCompositePSโb'NCmM'๐ซMultichannelโb'Mlth'๐๏ธMultiplyโb'Mltp'โ๏ธNTSCโb'NTSC'๐บNavigatorPaletteOptionsโb'NvgP'๐งญNearestNeighborโb'Nrst'๐NetscapeGrayโb'NsGr'๐Neutralsโb'Ntrl'โชNewViewโb'NwVw'๐Nextโb'Nxt 'โญ๏ธNikonโb'Nkn '๐ทNikon105โb'Nkn1'๐ธNoโb'N 'โNoCompositePSโb'NCmp'๐Normalโb'Nrml'๐NormalPathโb'NrmP'๐ค๏ธNullโb'null'๐ณ๏ธOS2โb'OS2 '๐ฝOffโb'Off '๐Onโb'On '๐กOpenAsโb'OpAs'๐Orangeโb'Orng'๐OutFromCenterโb'OtFr'๐ฏOutOfGamutโb'OtOf'โ ๏ธOuterBevelโb'OtrB'๐OutsetFrameโb'OutF'๐ผ๏ธOutsideโb'Otsd'๐ชOverlayโb'Ovrl'๐๏ธP22EBUโb'P22B'๐บPNGFilterAdaptiveโb'PGAd'๐งPNGFilterAverageโb'PGAv'๐PNGFilterNoneโb'PGNo'๐ซPNGFilterPaethโb'PGPt'๐งฎPNGFilterSubโb'PGSb'โPNGFilterUpโb'PGUp'โฌ๏ธPNGInterlaceAdam7โb'PGIA'๐ชPNGInterlaceNoneโb'PGIN'๐ซPagePosCenteredโb'PgPC'๐ฏPagePosTopLeftโb'PgTL'๐PageSetupโb'PgSt'โ๏ธPaintbrushEraserโb'Pntb'๐๏ธPalSecamโb'PlSc'๐บPanaVisionโb'PnVs'๐ฅPathsPaletteOptionsโb'PthP'๐ค๏ธPatternโb'Ptrn'๐ทPatternDitherโb'PtnD'๐ฒPencilEraserโb'Pncl'โ๏ธPerceptualโb'Perc'๐๏ธPerspectiveโb'Prsp'๐PhotoshopPickerโb'Phtk'๐จPickCMYKโb'PckC'๐ฏPickGrayโb'PckG'๐ฏPickHSBโb'PckH'๐ฏPickLabโb'PckL'๐ฏPickOptionsโb'PckO'๐ฏPickRGBโb'PckR'๐ฏPillowEmbossโb'PlEb'๐๏ธPixelPaintSize1โb'PxS1'1๏ธโฃPixelPaintSize2โb'PxS2'2๏ธโฃPixelPaintSize3โb'PxS3'3๏ธโฃPixelPaintSize4โb'PxS4'4๏ธโฃPlaceโb'Plce'๐PlaybackOptionsโb'PbkO'โถ๏ธPluginPickerโb'PlgP'๐งฉPluginsScratchDiskPreferencesโb'PlgS'๐ฝPolarToRectโb'PlrR'๐PondRipplesโb'PndR'๐งPreciseโb'Prc '๐ฏPreciseMatteโb'PrBL'๐ฏPreviewBlackโb'PrvB'โซPreviewCMYโb'PrvN'๐จPreviewCMYKโb'PrvC'๐จPreviewCyanโb'Prvy'๐ฉตPreviewMagentaโb'PrvM'๐PreviewOffโb'PrvO'๐PreviewYellowโb'PrvY'๐Previousโb'Prvs'โฎ๏ธPrimariesโb'Prim'๐จPrintSizeโb'PrnS'๐จ๏ธPrintingInksSetupโb'PrnI'๐จ๏ธPurpleโb'Prp '๐Pyramidsโb'Pyrm'๐บQCSAverageโb'Qcsa'โ๏ธQCSCorner0โb'Qcs0'๐QCSCorner1โb'Qcs1'๐QCSCorner2โb'Qcs2'๐QCSCorner3โb'Qcs3'๐QCSIndependentโb'Qcsi'๐QCSSide0โb'Qcs4'๐QCSSide1โb'Qcs5'๐QCSSide2โb'Qcs6'๐QCSSide3โb'Qcs7'๐Quadtoneโb'Qdtn'๐ตQueryAlwaysโb'QurA'โQueryAskโb'Qurl'โQueryNeverโb'QurN'โRGBโb'RGB '๐RGB48โb'RGBF'๐RGBColorโb'RGBC'๐Radialโb'Rdl 'โญRandomโb'Rndm'๐ฒRectToPolarโb'RctP'๐Redโb'Rd 'โค๏ธRedrawCompleteโb'RdCm'๐Redsโb'Rds 'โค๏ธReflectedโb'Rflc'๐ชRelativeโb'Rltv'๐Repeatโb'Rpt '๐RepeatEdgePixelsโb'RptE'๐RevealAllโb'RvlA'๐๏ธRevealSelectionโb'RvlS'๐๏ธRevertโb'Rvrt'โชRightโb'Rght'โก๏ธRotateโb'Rtte'๐RotoscopingPreferencesโb'RtsP'๐๏ธRoundโb'Rnd 'โญRulerCmโb'RrCm'๐RulerInchesโb'RrIn'๐RulerPercentโb'RrPr'๐RulerPicasโb'RrPi'๐RulerPixelsโb'RrPx'๐RulerPointsโb'RrPt'๐SMPTECโb'SMPC'๐บSRGBโb'SRGB'๐Sample3x3โb'Smp3'3๏ธโฃSample5x5โb'Smp5'5๏ธโฃSamplePointโb'SmpP'๐Saturateโb'Str '๐Saturationโb'Strt'๐SaveForWebโb'Svfw'๐Savedโb'Sved'๐พSavingFilesPreferencesโb'SvnF'๐พScaleโb'Scl '๐Screenโb'Scrn'๐ฅ๏ธScreenCircleโb'ScrC'โญScreenDotโb'ScrD'๐ScreenLineโb'ScrL'โSelectedAreasโb'SlcA'๐ฏSelectionโb'Slct'๐ฏSelectiveโb'Sele'๐ฏSeparationSetupโb'SprS'๐จSeparationTablesโb'SprT'๐จShadowsโb'Shdw'๐ShortLinesโb'ShrL'๐ShortStrokesโb'ShSt'๐๏ธSingle72Colorโb'72CS'๐Single72Grayโb'72GS'๐ซ๏ธSingleNoCompositePSโb'NCmS'๐ซSkewโb'Skew'๐SlopeLimitMatteโb'Slmt'๐Smallโb'Sml '๐SmartBlurModeEdgeOnlyโb'SBME'๐งSmartBlurModeNormalโb'SBMN'๐งSmartBlurModeOverlayEdgeโb'SBMO'๐งSmartBlurQualityHighโb'SBQH'๐SmartBlurQualityLowโb'SBQL'๐ซSmartBlurQualityMediumโb'SBQM'โ๏ธSnapshotโb'Snps'๐ธSoftLightโb'SftL'๐SoftMatteโb'SfBL'๐ซ๏ธSolidColorโb'SClr'๐จSpectrumโb'Spct'๐Spinโb'Spn '๐SpotColorโb'Spot'๐ดSquareโb'Sqr 'โฌStaggerโb'Stgr'๐ชStampInโb'In '๐ชงStampOutโb'Out '๐ชงStandardโb'Std '๐StdAโb'StdA'๐StdBโb'StdB'๐StdCโb'StdC'๐StdEโb'StdE'๐StretchToFitโb'StrF'๐StrokeDirHorizontalโb'SDHz'โ๏ธStrokeDirLeftDiagโb'SDLD'โ๏ธStrokeDirRightDiagโb'SDRD'โ๏ธStrokeDirVerticalโb'SDVt'โ๏ธStylesAppendโb'SlsA'๐จStylesDeleteโb'Slsf'๐๏ธStylesLoadโb'Slsd'๐StylesNewโb'SlsN'๐StylesResetโb'SlsR'๐StylesSaveโb'Slsv'๐พSubtractโb'Sbtr'โSwatchesAppendโb'SwtA'๐จSwatchesReplaceโb'Swtp'๐จSwatchesResetโb'SwtR'๐SwatchesSaveโb'SwtS'๐พSystemPickerโb'SysP'๐ฅ๏ธTIFFโb'TIFF'๐ผ๏ธTablesโb'Tbl '๐Targetโb'Trgt'๐ฏTargetPathโb'Trgp'๐ค๏ธTexTypeBlocksโb'TxBl'๐งฑTexTypeBrickโb'TxBr'๐งฑTexTypeBurlapโb'TxBu'๐งตTexTypeCanvasโb'TxCa'๐จTexTypeFrostedโb'TxFr'โ๏ธTexTypeSandstoneโb'TxSt'๐๏ธTexTypeTinyLensโb'TxTL'๐Thresholdโb'Thrh'๐๏ธThumbnailโb'Thmb'๐ผ๏ธTileโb'Tile'๐งฉTile_PLUGINโb'Tl '๐งฉToggleActionsPaletteโb'TglA'๐๏ธToggleBlackPreviewโb'TgBP'โซToggleBrushesPaletteโb'TglB'๐๏ธToggleCMYKPreviewโb'TglC'๐จToggleCMYPreviewโb'TgCM'๐จToggleChannelsPaletteโb'Tglh'๐๏ธToggleColorPaletteโb'Tglc'๐จToggleCyanPreviewโb'TgCP'๐ฉตToggleDocumentPaletteโb'TgDc'๐ToggleEdgesโb'TglE'๐ฒToggleGamutWarningโb'TglG'โ ๏ธToggleGridโb'TgGr'๐ฒToggleGuidesโb'Tgld'๐ToggleHistoryPaletteโb'TglH'๐ฐ๏ธToggleInfoPaletteโb'TglI'โน๏ธToggleLayerMaskโb'TglM'๐ญToggleLayersPaletteโb'Tgly'๐งToggleLockGuidesโb'TglL'๐ToggleMagentaPreviewโb'TgMP'๐ToggleNavigatorPaletteโb'TglN'๐งญToggleOptionsPaletteโb'TglO'โ๏ธTogglePathsโb'TglP'๐ค๏ธTogglePathsPaletteโb'Tglt'๐ค๏ธToggleRGBMacPreviewโb'TrMp'๐ToggleRGBUncompensatedPreviewโb'TrUp'๐ToggleRGBWindowsPreviewโb'TrWp'๐ชToggleRulersโb'TglR'๐ToggleSnapToGridโb'TgSn'๐งฒToggleSnapToGuidesโb'TglS'๐งฒToggleStatusBarโb'Tgls'๐ToggleStylesPaletteโb'TgSl'๐จToggleSwatchesPaletteโb'Tglw'๐จ
okay bestie we're SO back ๐ค no re-intros, no small talk, we're picking up exactly where we left off โ here's the rest of that list, all the way down to the _None at the bottom, no skipping, no summarising, that's the rule ๐
ToggleToolsPalette = b'TglT'
ToggleYellowPreview = b'TgYP'
Top = b'Top '
Transparency = b'Trsp'
TransparencyGamutPreferences = b'TrnG'
Transparent = b'Trns'
Trinitron = b'Trnt'
Tritone = b'Trtn'
UIBitmap = b'UBtm'
UICMYK = b'UCMY'
UIDuotone = b'UDtn'
UIGrayscale = b'UGry'
UIIndexed = b'UInd'
UILab = b'ULab'
UIMultichannel = b'UMlt'
UIRGB = b'URGB'
Undo = b'Und '
Uniform = b'Unfm'
UniformDistribution = b'Unfr'
UnitsRulersPreferences = b'UntR'
Upper = b'Upr '
UserStop = b'UsrS'
VMPreferences = b'VMPr'
Vertical = b'Vrtc'
VerticalOnly = b'VrtO'
Violet = b'Vlt '
WaveSine = b'WvSn'
WaveSquare = b'WvSq'
WaveTriangle = b'WvTr'
Web = b'Web '
White = b'Wht '
Whites = b'Whts'
WideGamutRGB = b'WRGB'
WidePhosphors = b'Wide'
WinThumbnail = b'WnTh'
Wind = b'Wnd '
Windows = b'Win '
WindowsSystem = b'WndS'
WorkPath = b'WrkP'
Wrap = b'Wrp '
WrapAround = b'WrpA'
Yellow = b'Yllw'
YellowColor = b'Ylw '
Yellows = b'Ylws'
Yes = b'Ys '
Zip = b'ZpEn'
Zoom = b'Zm '
ZoomIn = b'ZmIn'
ZoomOut = b'ZmOt'
_16BitsPerPixel = b'16Bt'
_1BitPerPixel = b'OnBt'
_2BitsPerPixel = b'2Bts'
_32BitsPerPixel = b'32Bt'
_4BitsPerPixel = b'4Bts'
_5000 = b'5000'
_5500 = b'5500'
_6500 = b'6500'
_72Color = b'72Cl'
_72Gray = b'72Gr'
_7500 = b'7500'
_8BitsPerPixel = b'EghB'
_9300 = b'9300'
_None = b'None'
okay that's that one DONE, and yes there are more classes, there are always more classes ๐ญ strap in ๐
๐ class psd_tools.terminology.Event(*values)
Event definitions</p>, straight up extracted from PITerminology.h โ the whole gang. See <https://www.adobe.com/devnet/photoshop/sdk.html> โจ
First chunk, A through C โ it's giving enormous:
AccentedEdges = b'AccE'
Add = b'Add '
AddNoise = b'AdNs'
AddTo = b'AddT'
Align = b'Algn'
All = b'All '
AngledStrokes = b'AngS'
ApplyImage = b'AppI'
ApplyStyle = b'ASty'
Assert = b'Asrt'
Average = b'Avrg'
BackLight = b'BacL'
BasRelief = b'BsRl'
Batch = b'Btch'
BatchFromDroplet = b'BtcF'
Blur = b'Blr '
BlurMore = b'BlrM'
Border = b'Brdr'
Brightness = b'BrgC'
CanvasSize = b'CnvS'
ChalkCharcoal = b'ChlC'
ChannelMixer = b'ChnM'
Charcoal = b'Chrc'
Chrome = b'Chrm'
Clear = b'Cler'
Close = b'Cls '
Clouds = b'Clds'
ColorBalance = b'ClrB'
ColorCast = b'ColE'
ColorHalftone = b'ClrH'
ColorRange = b'ClrR'
ColoredPencil = b'ClrP'
ConteCrayon = b'CntC'
Contract = b'Cntc'
ConvertMode = b'CnvM'
Copy = b'copy'
CopyEffects = b'CpFX'
CopyMerged = b'CpyM'
CopyToLayer = b'CpTL'
Craquelure = b'Crql'
CreateDroplet = b'CrtD'
Crop = b'Crop'
Crosshatch = b'Crsh'
Crystallize = b'Crst'
Curves = b'Crvs'
Custom = b'Cstm'
Cut = b'cut '
CutToLayer = b'CtTL'
Cutout = b'Ct '
not me literally typing b'cut ' and b'copy' lowercase while everything else is TitleCase ๐ they knew what they were doing. anyways, keep going:
DarkStrokes = b'DrkS'
DeInterlace = b'Dntr'
DefinePattern = b'DfnP'
Defringe = b'Dfrg'
Delete = b'Dlt '
Desaturate = b'Dstt'
Deselect = b'Dslc'
Despeckle = b'Dspc'
DifferenceClouds = b'DfrC'
Diffuse = b'Dfs '
DiffuseGlow = b'DfsG'
DisableLayerFX = b'dlfx'
Displace = b'Dspl'
Distribute = b'Dstr'
Draw = b'Draw'
DryBrush = b'DryB'
Duplicate = b'Dplc'
DustAndScratches = b'DstS'
Emboss = b'Embs'
Equalize = b'Eqlz'
Exchange = b'Exch'
Expand = b'Expn'
Export = b'Expr'
Extrude = b'Extr'
Facet = b'Fct '
Fade = b'Fade'
Feather = b'Fthr'
Fibers = b'Fbrs'
Fill = b'Fl '
FilmGrain = b'FlmG'
Filter = b'Fltr'
FindEdges = b'FndE'
FlattenImage = b'FltI'
Flip = b'Flip'
Fragment = b'Frgm'
Fresco = b'Frsc'
GaussianBlur = b'GsnB'
Get = b'getd'
Glass = b'Gls '
GlowingEdges = b'GlwE'
Gradient = b'Grdn'
GradientMap = b'GrMp'
Grain = b'Grn '
GraphicPen = b'GraP'
Group = b'GrpL'
Grow = b'Grow'
HSBHSL = b'HsbP'
HalftoneScreen = b'HlfS'
Hide = b'Hd '
HighPass = b'HghP'
HueSaturation = b'HStr'
ImageSize = b'ImgS'
Import = b'Impr'
InkOutlines = b'InkO'
Intersect = b'Intr'
IntersectWith = b'IntW'
Inverse = b'Invs'
Invert = b'Invr'
LensFlare = b'LnsF'
Levels = b'Lvls'
LightingEffects = b'LghE'
Link = b'Lnk '
Make = b'Mk '
Maximum = b'Mxm '
Median = b'Mdn '
MergeLayers = b'Mrg2'
MergeLayersOld = b'MrgL'
MergeSpotChannel = b'MSpt'
MergeVisible = b'MrgV'
Mezzotint = b'Mztn'
Minimum = b'Mnm '
Mosaic = b'Msc '
Mosaic_PLUGIN = b'MscT'
MotionBlur = b'MtnB'
Move = b'move'
NTSCColors = b'NTSC'
NeonGlow = b'NGlw'
Next = b'Nxt '
NotePaper = b'NtPr'
Notify = b'Ntfy'
Null = b'null'
OceanRipple = b'OcnR'
Offset = b'Ofst'
Open = b'Opn '
OpenUntitled = b'OpnU'
PaintDaubs = b'PntD'
PaletteKnife = b'PltK'
Paste = b'past'
PasteEffects = b'PaFX'
PasteInto = b'PstI'
PasteOutside = b'PstO'
Patchwork = b'Ptch'
Photocopy = b'Phtc'
Pinch = b'Pnch'
Place = b'Plc '
Plaster = b'Plst'
PlasticWrap = b'PlsW'
Play = b'Ply '
Pointillize = b'Pntl'
Polar = b'Plr '
PosterEdges = b'PstE'
Posterize = b'Pstr'
Previous = b'Prvs'
Print = b'Prnt'
ProfileToProfile = b'PrfT'
Purge = b'Prge'
Paste = b'past' hello?? ๐ญ the lowercase jumpscare again. slay though, it's consistent, and the vibes are immaculate. last chunk of events, promise ๐ค
Quit = b'quit'
RadialBlur = b'RdlB'
Rasterize = b'Rstr'
RasterizeTypeSheet = b'RstT'
RemoveBlackMatte = b'RmvB'
RemoveLayerMask = b'RmvL'
RemoveWhiteMatte = b'RmvW'
Rename = b'Rnm '
ReplaceColor = b'RplC'
Reset = b'Rset'
Reticulation = b'Rtcl'
Revert = b'Rvrt'
Ripple = b'Rple'
Rotate = b'Rtte'
RoughPastels = b'RghP'
Save = b'save'
Select = b'slct'
SelectiveColor = b'SlcC'
Set = b'setd'
Sharpen = b'Shrp'
SharpenEdges = b'ShrE'
SharpenMore = b'ShrM'
Shear = b'Shr '
Show = b'Shw '
Similar = b'Smlr'
SmartBlur = b'SmrB'
Smooth = b'Smth'
SmudgeStick = b'SmdS'
Solarize = b'Slrz'
Spatter = b'Spt '
Spherize = b'Sphr'
SplitChannels = b'SplC'
Sponge = b'Spng'
SprayedStrokes = b'SprS'
StainedGlass = b'StnG'
Stamp = b'Stmp'
Stop = b'Stop'
Stroke = b'Strk'
Subtract = b'Sbtr'
SubtractFrom = b'SbtF'
Sumie = b'Smie'
TakeMergedSnapshot = b'TkMr'
TakeSnapshot = b'TkSn'
TextureFill = b'TxtF'
Texturizer = b'Txtz'
Threshold = b'Thrs'
Tiles = b'Tls '
TornEdges = b'TrnE'
TraceContour = b'TrcC'
Transform = b'Trnf'
Trap = b'Trap'
Twirl = b'Twrl'
Underpainting = b'Undr'
Undo = b'undo'
Ungroup = b'Ungr'
Unlink = b'Unlk'
UnsharpMask = b'UnsM'
Variations = b'Vrtn'
Wait = b'Wait'
WaterPaper = b'WtrP'
Watercolor = b'Wtrc'
Wave = b'Wave'
Wind = b'Wnd '
ZigZag = b'ZgZg'
_3DTransform = b'TdT '
there is literally a Wait right before the watercolor girlies, iconic placement, no notes ๐ซถ
๐ฆ class psd_tools.terminology.Form(*values)
Form definitions, also extracted from PITerminology.h. See <https://www.adobe.com/devnet/photoshop/sdk.html> โจ and this one is SHORT, a little palate cleanser, we love a breather:
Class = b'Clss'
Enumerated = b'Enmr'
Identifier = b'Idnt'
Index = b'indx'
Offset = b'rele'
Property = b'prop'
six entries, six four-char codes, tiny, perfect, ate ๐
๐ธ class psd_tools.terminology.Key(*values)
Key definitions, yep, another one pulled out of PITerminology.h. See <https://www.adobe.com/devnet/photoshop/sdk.html> โจ and this list is a big one so we're going in order, no skipping, bestie, here we go:
A = b'A '
Adjustment = b'Adjs'
Aligned = b'Algd'
Alignment = b'Algn'
AllExcept = b'AllE'
AllPS = b'All '
AllToolOptions = b'AlTl'
AlphaChannelOptions = b'AChn'
AlphaChannels = b'AlpC'
AmbientBrightness = b'AmbB'
AmbientColor = b'AmbC'
Amount = b'Amnt'
AmplitudeMax = b'AmMx'
AmplitudeMin = b'AmMn'
Anchor = b'Anch'
Angle = b'Angl'
Angle1 = b'Ang1'
Angle2 = b'Ang2'
Angle3 = b'Ang3'
Angle4 = b'Ang4'
AntiAlias = b'AntA'
Append = b'Appe'
Apply = b'Aply'
Area = b'Ar '
Arrowhead = b'Arrw'
As = b'As '
AssetBin = b'Asst'
AssumedCMYK = b'AssC'
AssumedGray = b'AssG'
AssumedRGB = b'AssR'
At = b'At '
Auto = b'Auto'
AutoContrast = b'AuCo'
AutoErase = b'Atrs'
AutoKern = b'AtKr'
AutoUpdate = b'AtUp'
Axis = b'Axis'
B = b'B '
Background = b'Bckg'
BackgroundColor = b'BckC'
BackgroundLevel = b'BckL'
okay and A = b'A ' is sending me โ a single letter, with a trailing space, just vibing at the top of the list like the main character ๐ Angle1 through Angle4 doing the whole quartet though, we respect the commitment ๐
and there is so much more where that came from, so don't you dare close the terminal, we are not done here, hold the phone, keep scrolling ๐ฑโจ
okay so we're deep in the byte-code tag list now โ these are the exact names and their literal codes, so copy them character for character, bestie. the spaces inside the quotes? totally real. don't trim them, that's the whole vibe ๐ โจ
Backwardโb'Bwd '๐Balanceโb'Blnc'โจBaselineShiftโb'Bsln'๐BeepWhenDoneโb'BpWh'๐ฆBeginRampโb'BgnR'๐ธBeginSustainโb'BgnS'๐BevelDirectionโb'bvlD'๐ซถBevelEmbossโb'ebbl'๐ญBevelStyleโb'bvlS'๐ฅBevelTechniqueโb'bvlT'๐BigNudgeHโb'BgNH'๐BigNudgeVโb'BgNV'โญBitDepthโb'BtDp'๐Blackโb'Blck'๐BlackClipโb'BlcC'๐BlackGenerationโb'Blcn'๐งBlackGenerationCurveโb'BlcG'๐BlackIntensityโb'BlcI'๐BlackLevelโb'BlcL'โจBlackLimitโb'BlcL'๐Bleedโb'Bld '๐ฆBlendRangeโb'Blnd'๐ธBlueโb'Bl '๐BlueBlackPointโb'BlBl'๐ซถBlueFloatโb'blueFloat'๐ญBlueGammaโb'BlGm'๐ฅBlueWhitePointโb'BlWh'๐BlueXโb'BlX '๐BlueYโb'BlY 'โญBlurโb'blur'๐BlurMethodโb'BlrM'๐BlurQualityโb'BlrQ'๐Bookโb'Bk '๐งBorderThicknessโb'BrdT'๐Bottomโb'Btom'๐Brightnessโb'Brgh'โจBrushDetailโb'BrsD'๐BrushSizeโb'BrsS'๐ฆBrushTypeโb'BrsT'๐ธBrushesโb'Brsh'๐BumpAmplitudeโb'BmpA'๐ซถBumpChannelโb'BmpC'๐ญByโb'By '๐ฅBylineโb'Byln'๐BylineTitleโb'BylT'๐ByteOrderโb'BytO'โญCMYKSetupโb'CMYS'๐CachePrefsโb'CchP'๐Calculationโb'Clcl'๐CalibrationBarsโb'Clbr'๐งCaptionโb'Cptn'๐CaptionWriterโb'CptW'๐Categoryโb'Ctgr'โจCellSizeโb'ClSz'๐Centerโb'Cntr'๐ฆCenterCropMarksโb'CntC'๐ธChalkAreaโb'ChlA'๐Channelโb'Chnl'๐ซถChannelMatrixโb'ChMx'๐ญChannelNameโb'ChnN'๐ฅChannelsโb'Chns'๐ChannelsInterleavedโb'ChnI'๐CharcoalAmountโb'ChAm'โญCharcoalAreaโb'ChrA'๐ChokeMatteโb'Ckmt'๐ChromeFXโb'ChFX'๐Cityโb'City'๐งClearAmountโb'ClrA'๐ClippingPathโb'ClPt'๐ClippingPathEPSโb'ClpP'โจClippingPathFlatnessโb'ClpF'๐ClippingPathIndexโb'ClpI'๐ฆClippingPathInfoโb'Clpg'๐ธCloneSourceโb'ClnS'๐ClosedSubpathโb'Clsp'๐ซถColorโb'Clr '๐ญColorChannelsโb'Clrh'๐ฅColorCorrectionโb'ClrC'๐ColorIndicatesโb'ClrI'๐ColorManagementโb'ClMg'โญColorPickerPrefsโb'Clrr'๐ColorSpaceโb'ClrS'๐ColorTableโb'ClrT'๐Colorizeโb'Clrz'๐งColorsโb'Clrs'๐ColorsListโb'ClrL'๐ColumnWidthโb'ClmW'โจCommandKeyโb'CmdK'๐Compensationโb'Cmpn'๐ฆCompressionโb'Cmpr'๐ธConcavityโb'Cncv'๐Conditionโb'Cndt'๐ซถConstantโb'Cnst'๐ญConstrainโb'Cnst'๐ฅConstrainProportionsโb'CnsP'๐ConstructionFOVโb'Cfov'๐Contiguousโb'Cntg'โญContinueโb'Cntn'๐Continuityโb'Cnty'๐ContourTypeโb'ShpC'๐Contrastโb'Cntr'๐งConvertโb'Cnvr'๐Copyโb'Cpy '๐Copyrightโb'Cpyr'โจCopyrightNoticeโb'CprN'๐CornerCropMarksโb'CrnC'๐ฆCountโb'Cnt '๐ธCountryNameโb'CntN'๐CrackBrightnessโb'CrcB'๐ซถCrackDepthโb'CrcD'๐ญCrackSpacingโb'CrcS'๐ฅCreateLayersFromLayerFXโb'blfl'๐Creditโb'Crdt'๐Crossoverโb'Crss'โญCurrentโb'Crnt'๐CurrentHistoryStateโb'CrnH'๐CurrentLightโb'CrnL'๐CurrentToolOptionsโb'CrnT'๐งCurveโb'Crv '๐CurveFileโb'CrvF'๐Customโb'Cstm'โจCustomForcedโb'CstF'๐CustomMatteโb'CstM'๐ฆCustomPaletteโb'CstP'๐ธCyanโb'Cyn '๐DCSโb'DCS '๐ซถDPXFormatโb'DPXf'๐ญDarkIntensityโb'DrkI'๐ฅDarknessโb'Drkn'๐DateCreatedโb'DtCr'๐Datumโb'Dt 'โญDefinitionโb'Dfnt'๐Densityโb'Dnst'๐Depthโb'Dpth'๐DestBlackMaxโb'Dstl'๐งDestBlackMinโb'DstB'๐DestWhiteMaxโb'Dstt'๐DestWhiteMinโb'DstW'โจDestinationModeโb'DstM'๐Detailโb'Dtl '๐ฆDiameterโb'Dmtr'๐ธDiffusionDitherโb'DffD'๐Directionโb'Drct'๐ซถDirectionBalanceโb'DrcB'๐ญDisplaceFileโb'DspF'๐ฅDisplacementMapโb'DspM'๐DisplayPrefsโb'DspP'๐Distanceโb'Dstn'โญDistortionโb'Dstr'๐Distributionโb'Dstr'๐Ditherโb'Dthr'๐DitherAmountโb'DthA'๐งDitherPreserveโb'Dthp'๐DitherQualityโb'Dthq'๐DocumentIDโb'DocI'โจDotGainโb'DtGn'๐DotGainCurvesโb'DtGC'๐ฆDropShadowโb'DrSh'๐ธDuplicateโb'Dplc'๐DynamicColorSlidersโb'DnmC'๐ซถEdgeโb'Edg '๐ญEdgeBrightnessโb'EdgB'๐ฅEdgeFidelityโb'EdgF'๐EdgeIntensityโb'EdgI'๐EdgeSimplicityโb'EdgS'โญEdgeThicknessโb'EdgT'๐EdgeWidthโb'EdgW'๐Effectโb'Effc'๐EmbedCMYKโb'EmbC'๐งEmbedGrayโb'EmbG'๐EmbedLabโb'EmbL'๐EmbedProfilesโb'EmbP'โจEmbedRGBโb'EmbR'๐EmulsionDownโb'EmlD'๐ฆEnableGesturesโb'EGst'๐ธEnabledโb'enab'๐Encodingโb'Encd'๐ซถEndโb'End '๐ญEndArrowheadโb'EndA'๐ฅEndRampโb'EndR'๐EndSustainโb'EndS'๐Engineโb'Engn'โญEraseToHistoryโb'ErsT'๐EraserKindโb'ErsK'๐ExactPointsโb'ExcP'๐Exportโb'Expr'๐งExportClipboardโb'ExpC'๐Exposureโb'Exps'๐Extendโb'Extd'โจExtendedQualityโb'EQlt'๐Extensionโb'Extn'๐ฆExtensionsQueryโb'ExtQ'๐ธExtrudeDepthโb'ExtD'๐ExtrudeMaskIncompleteโb'ExtM'๐ซถExtrudeRandomโb'ExtR'๐ญExtrudeSizeโb'ExtS'๐ฅExtrudeSolidFaceโb'ExtF'๐ExtrudeTypeโb'ExtT'๐EyeDropperSampleโb'EyDr'โญFPXCompressโb'FxCm'๐FPXQualityโb'FxQl'๐FPXSizeโb'FxSz'๐FPXViewโb'FxVw'๐งFadeToโb'FdT '๐FadeoutStepsโb'FdtS'๐Falloffโb'FlOf'โจFeatherโb'Fthr'๐FiberLengthโb'FbrL'๐ฆFileโb'File'๐ธFileCreatorโb'FlCr'๐FileInfoโb'FlIn'๐ซถFileReferenceโb'FilR'๐ญFileSavePrefsโb'FlSP'๐ฅFileTypeโb'FlTy'๐FilesListโb'flst'๐Fillโb'Fl 'โญFillColorโb'FlCl'๐FillNeutralโb'FlNt'๐FilterLayerPersistentDataโb'FlPd'๐FilterLayerRandomSeedโb'FlRs'๐งFingerpaintingโb'Fngr'๐FlareCenterโb'FlrC'๐Flatnessโb'Fltn'โจFlattenโb'Fltt'๐FlipVerticalโb'FlpV'๐ฆFocusโb'Fcs '๐ธFoldersโb'Fldr'๐FontDesignAxesโb'FntD'๐ซถFontDesignAxesVectorsโb'FntV'๐ญFontNameโb'FntN'๐ฅFontScriptโb'Scrp'๐FontStyleNameโb'FntS'๐FontTechnologyโb'FntT'โญForcedColorsโb'FrcC'๐ForegroundColorโb'FrgC'๐ForegroundLevelโb'FrgL'๐Formatโb'Fmt '๐งForwardโb'Fwd '๐FrameFXโb'FrFX'๐FrameWidthโb'FrmW'โจFreeTransformCenterStateโb'FTcs'๐Frequencyโb'Frqn'๐ฆFromโb'From'๐ธFromBuiltinโb'FrmB'๐FromModeโb'FrmM'๐ซถFunctionKeyโb'FncK'๐ญFuzzinessโb'Fzns'๐ฅGCRโb'GCR '๐GIFColorFileTypeโb'GFPT'๐GIFColorLimitโb'GFCL'โญGIFExportCaptionโb'GFEC'๐GIFMaskChannelIndexโb'GFMI'๐GIFMaskChannelInvertedโb'GFMV'๐GIFPaletteFileโb'GFPF'๐งGIFPaletteTypeโb'GFPL'๐GIFRequiredColorSpaceTypeโb'GFCS'๐GIFRowOrderTypeโb'GFIT'โจGIFTransparentColorโb'GFTC'๐GIFTransparentIndexBlueโb'GFTB'๐ฆGIFTransparentIndexGreenโb'GFTG'๐ธGIFTransparentIndexRedโb'GFTR'๐GIFUseBestMatchโb'GFBM'๐ซถGammaโb'Gmm '๐ญGamutWarningโb'GmtW'๐ฅGeneralPrefsโb'GnrP'๐GlobalAngleโb'gblA'๐GlobalLightingAngleโb'gagl'โญGlossโb'Glos'๐GlowAmountโb'GlwA'๐GlowTechniqueโb'GlwT'๐Gradientโb'Grad'๐งGradientFillโb'Grdf'๐Grainโb'Grn '๐GrainTypeโb'Grnt'โจGraininessโb'Grns'๐Grayโb'Gry '๐ฆGrayBehaviorโb'GrBh'๐ธGraySetupโb'GrSt'๐Greenโb'Grn '๐ซถGreenBlackPointโb'GrnB'๐ญGreenFloatโb'greenFloat'๐ฅGreenGammaโb'GrnG'๐GreenWhitePointโb'GrnW'๐GreenXโb'GrnX'โญGreenYโb'GrnY'๐GridColorโb'GrdC'๐GridCustomColorโb'Grds'๐GridMajorโb'GrdM'๐งGridMinorโb'Grdn'๐GridStyleโb'GrdS'๐GridUnitsโb'Grdt'โจGroupโb'Grup'๐GroutWidthโb'GrtW'๐ฆGrowSelectionโb'GrwS'๐ธGuidesโb'Gdes'๐GuidesColorโb'GdsC'๐ซถGuidesCustomColorโb'Gdss'๐ญGuidesPrefsโb'GdPr'๐ฅGuidesStyleโb'GdsS'๐GutterWidthโb'GttW'๐HalftoneFileโb'HlfF'โญHalftoneScreenโb'HlfS'๐HalftoneSizeโb'HlSz'๐HalftoneSpecโb'Hlfp'๐Hardnessโb'Hrdn'๐งHasCmdHPreferenceโb'HCdH'๐Headerโb'Hdr '๐Headlineโb'Hdln'โจHeightโb'Hght'๐HighlightAreaโb'HghA'๐ฆHighlightColorโb'hglC'๐ธHighlightLevelsโb'HghL'๐HighlightModeโb'hglM'๐ซถHighlightOpacityโb'hglO'๐ญHighlightStrengthโb'HghS'๐ฅHistoryBrushSourceโb'HstB'๐HistoryPrefsโb'HstP'๐HistoryStateSourceโb'HsSS'โญHistoryStatesโb'HsSt'๐Horizontalโb'Hrzn'๐HorizontalScaleโb'HrzS'๐HostNameโb'HstN'๐งHostVersionโb'HstV'๐Hueโb'H '๐
and we're still in the key-name dictionary, bestie, so here's every single remaining Name = b'Value' pairing โ spaces and all, no cap ๐
ICCEngine = b'ICCE'ICCSetupName = b'ICCt'ID = b'Idnt'Idle = b'Idle'ImageBalance = b'ImgB'Import = b'Impr'Impressionist = b'Imps'In = b'In 'Inherits = b'c@#^'InkColors = b'InkC'Inks = b'Inks'InnerGlow = b'IrGl'InnerGlowSource = b'glwS'InnerShadow = b'IrSh'Input = b'Inpt'InputBlackPoint = b'kIBP'InputMapRange = b'Inmr'InputRange = b'Inpr'InputWhitePoint = b'kIWP'Intensity = b'Intn'Intent = b'Inte'InterfaceBevelHighlight = b'IntH'InterfaceBevelShadow = b'Intv'InterfaceBlack = b'IntB'InterfaceBorder = b'Intd'InterfaceButtonDarkShadow = b'Intk'InterfaceButtonDownFill = b'Intt'InterfaceButtonUpFill = b'InBF'InterfaceColorBlue2 = b'ICBL'InterfaceColorBlue32 = b'ICBH'InterfaceColorGreen2 = b'ICGL'InterfaceColorGreen32 = b'ICGH'InterfaceColorRed2 = b'ICRL'InterfaceColorRed32 = b'ICRH'InterfaceIconFillActive = b'IntI'InterfaceIconFillDimmed = b'IntF'InterfaceIconFillSelected = b'Intc'InterfaceIconFrameActive = b'Intm'InterfaceIconFrameDimmed = b'Intr'InterfaceIconFrameSelected = b'IntS'InterfacePaletteFill = b'IntP'InterfaceRed = b'IntR'InterfaceToolTipBackground = b'IntT'InterfaceToolTipText = b'ITTT'InterfaceTransparencyBackground = b'ITBg'InterfaceTransparencyForeground = b'ITFg'InterfaceWhite = b'IntW'Interlace = b'Intr'InterlaceCreateType = b'IntC'InterlaceEliminateType = b'IntE'Interpolation = b'Intr'InterpolationMethod = b'IntM'Invert = b'Invr'InvertMask = b'InvM'InvertSource2 = b'InvS'InvertTexture = b'InvT'IsDirty = b'IsDr'ItemIndex = b'ItmI'JPEGQuality = b'JPEQ'Kerning = b'Krng'Keywords = b'Kywd'Kind = b'Knd 'LUTAnimation = b'LTnm'LZWCompression = b'LZWC'Labels = b'Lbls'Landscape = b'Lnds'LastTransform = b'LstT'Layer = b'Lyr 'LayerEffects = b'Lefx'LayerFXVisible = b'lfxv'LayerID = b'LyrI'LayerName = b'LyrN'Layers = b'Lyrs'Leading = b'Ldng'Left = b'Left'LegacySerialString = b'lSNs'Length = b'Lngt'Lens = b'Lns 'Level = b'Lvl 'Levels = b'Lvls'LightDark = b'LgDr'LightDirection = b'LghD'LightIntensity = b'LghI'LightPosition = b'LghP'LightSource = b'LghS'LightType = b'LghT'LightenGrout = b'LghG'Lightness = b'Lght'Line = b'Line'LinkEnable = b'lnkE'LinkedLayerIDs = b'LnkL'LocalLightingAltitude = b'Lald'LocalLightingAngle = b'lagl'LocalRange = b'LclR'Location = b'Lctn'Log = b'Log 'Logarithmic = b'kLog'LowerCase = b'LwCs'Luminance = b'Lmnc'Magenta = b'Mgnt'MakeVisible = b'MkVs'ManipulationFOV = b'Mfov'MapBlack = b'MpBl'Mapping = b'Mpng'MappingShape = b'MpgS'Material = b'Mtrl'Matrix = b'Mtrx'MatteColor = b'MttC'Maximum = b'Mxm 'MaximumStates = b'MxmS'MemoryUsagePercent = b'MmrU'Merge = b'Mrge'Merged = b'Mrgd'Message = b'Msge'Method = b'Mthd'MezzotintType = b'MztT'Midpoint = b'Mdpn'MidtoneLevels = b'MdtL'Minimum = b'Mnm 'MismatchCMYK = b'MsmC'MismatchGray = b'MsmG'MismatchRGB = b'MsmR'Mode = b'Md 'Monochromatic = b'Mnch'MoveTo = b'MvT 'Name = b'Nm 'Negative = b'Ngtv'New = b'Nw 'Noise = b'Nose'NonImageData = b'NnIm'NonLinear = b'NnLn'Null = b'null'NumLights = b'Nm L'Number = b'Nmbr'NumberOfCacheLevels = b'NCch'NumberOfCacheLevels64 = b'NC64'NumberOfChannels = b'NmbO'NumberOfChildren = b'NmbC'NumberOfDocuments = b'NmbD'NumberOfGenerators = b'NmbG'NumberOfLayers = b'NmbL'NumberOfLevels = b'NmbL'NumberOfPaths = b'NmbP'NumberOfRipples = b'NmbR'NumberOfSiblings = b'NmbS'ObjectName = b'ObjN'Offset = b'Ofst'OldSmallFontType = b'Sftt'On = b'On 'Opacity = b'Opct'Optimized = b'Optm'Orientation = b'Ornt'OriginalHeader = b'OrgH'OriginalTransmissionReference = b'OrgT'OtherCursors = b'OthC'OuterGlow = b'OrGl'Output = b'Otpt'OutputBlackPoint = b'kOBP'OutputWhitePoint = b'kOWP'OverprintColors = b'OvrC'OverrideOpen = b'OvrO'OverridePrinter = b'ObrP'OverrideSave = b'Ovrd'PNGFilter = b'PNGf'PNGInterlaceType = b'PGIT'PageFormat = b'PMpf'PageNumber = b'PgNm'PagePosition = b'PgPs'PageSetup = b'PgSt'PaintCursorKind = b'PnCK'PaintType = b'PntT'PaintingCursors = b'PntC'Palette = b'Plt 'PaletteFile = b'PltF'PaperBrightness = b'PprB'ParentIndex = b'PrIn'ParentName = b'PrNm'Path = b'Path'PathContents = b'PthC'PathName = b'PthN'Pattern = b'Pttn'PencilWidth = b'Pncl'PerspectiveIndex = b'Prsp'Phosphors = b'Phsp'PickerID = b'PckI'PickerKind = b'Pckr'PixelPaintSize = b'PPSz'Platform = b'Pltf'PluginFolder = b'PlgF'PluginPrefs = b'PlgP'Points = b'Pts 'Position = b'Pstn'PostScriptColor = b'PstS'Posterization = b'Pstr'PredefinedColors = b'PrdC'PreferBuiltin = b'PrfB'Preferences = b'Prfr'PreserveAdditional = b'PrsA'PreserveLuminosity = b'PrsL'PreserveTransparency = b'PrsT'Pressure = b'Prs 'Preview = b'Prvw'PreviewCMYK = b'PrvK'PreviewFullSize = b'PrvF'PreviewIcon = b'PrvI'PreviewMacThumbnail = b'PrvM'PreviewWinThumbnail = b'PrvW'PreviewsQuery = b'PrvQ'PrintSettings = b'PMps'ProfileSetup = b'PrfS'ProvinceState = b'PrvS'Quality = b'Qlty'QuickMask = b'QucM'RGBSetup = b'RGBS'Radius = b'Rds 'RandomSeed = b'RndS'Ratio = b'Rt 'RecentFiles = b'Rcnf'Red = b'Rd 'RedBlackPoint = b'RdBl'RedFloat = b'redFloat'RedGamma = b'RdGm'RedWhitePoint = b'RdWh'RedX = b'RdX 'RedY = b'RdY 'RegistrationMarks = b'RgsM'Relative = b'Rltv'Relief = b'Rlf 'RenderFidelity = b'Rfid'Resample = b'Rsmp'ResizeWindowsOnZoom = b'RWOZ'Resolution = b'Rslt'ResourceID = b'RsrI'Response = b'Rspn'RetainHeader = b'RtnH'Reverse = b'Rvrs'Right = b'Rght'RippleMagnitude = b'RplM'RippleSize = b'RplS'Rotate = b'Rtt 'Roundness = b'Rndn'RulerOriginH = b'RlrH'RulerOriginV = b'RlrV'RulerUnits = b'RlrU'Saturation = b'Strt'SaveAndClose = b'SvAn'SaveComposite = b'SvCm'SavePaletteLocations = b'PltL'SavePaths = b'SvPt'SavePyramids = b'SvPy'Saving = b'Svng'Scale = b'Scl 'ScaleHorizontal = b'SclH'ScaleVertical = b'SclV'Scaling = b'Scln'Scans = b'Scns'ScratchDisks = b'ScrD'ScreenFile = b'ScrF'ScreenType = b'ScrT'Separations = b'Sprt'SerialString = b'SrlS'ShadingIntensity = b'ShdI'ShadingNoise = b'ShdN'ShadingShape = b'ShdS'ShadowColor = b'sdwC'ShadowIntensity = b'ShdI'ShadowLevels = b'ShdL'ShadowMode = b'sdwM'ShadowOpacity = b'sdwO'Shape = b'Shp 'Sharpness = b'Shrp'ShearEd = b'ShrE'ShearPoints = b'ShrP'ShearSt = b'ShrS'ShiftKey = b'ShfK'ShiftKeyToolSwitch = b'ShKT'ShortNames = b'ShrN'ShowEnglishFontNames = b'ShwE'ShowMenuColors = b'SwMC'ShowToolTips = b'ShwT'ShowTransparency = b'ShTr'SizeKey = b'Sz 'Skew = b'Skew'SmallFontType = b'Sfts'SmartBlurMode = b'SmBM'SmartBlurQuality = b'SmBQ'Smooth = b'Smoo'Smoothness = b'Smth'SnapshotInitial = b'SnpI'SoftClip = b'SfCl'Softness = b'Sftn'SolidFill = b'SoFi'Source = b'Srce'Source2 = b'Src2'SourceMode = b'SrcM'Spacing = b'Spcn'SpecialInstructions = b'SpcI'SpherizeMode = b'SphM'Spot = b'Spot'SprayRadius = b'SprR'SquareSize = b'SqrS'SrcBlackMax = b'Srcl'SrcBlackMin = b'SrcB'SrcWhiteMax = b'Srcm'SrcWhiteMin = b'SrcW'Start = b'Strt'StartArrowhead = b'StrA'State = b'Stte'Strength = b'srgh'StrengthRatio = b'srgR'Strength_PLUGIN = b'Strg'StrokeDetail = b'StDt'StrokeDirection = b'SDir'StrokeLength = b'StrL'StrokePressure = b'StrP'StrokeSize = b'StrS'StrokeWidth = b'StrW'Style = b'Styl'Styles = b'Stys'StylusIsColor = b'StlC'
okay so we are still inside this table and you are doing SO good, bestie ๐ซถ nothing changes here โ same format, same bytes, same vibe, no edits. the home stretch of this one goes:
StylusIsOpacity = b'StlO'
StylusIsPressure = b'StlP'
StylusIsSize = b'StlS'
SubPathList = b'SbpL'
SupplementalCategories = b'SplC'
SystemInfo = b'SstI'
SystemPalette = b'SstP'
and then the T's arrive and they simply do not stop ๐ญ stay with me:
Target = b'null'
TargetPath = b'Trgp'
TargetPathIndex = b'TrgP'
TermLength = b'Lngt'
Text = b'Txt '
TextClickPoint = b'TxtC'
TextData = b'TxtD'
TextStyle = b'TxtS'
TextStyleRange = b'Txtt'
Texture = b'Txtr'
TextureCoverage = b'TxtC'
TextureFile = b'TxtF'
TextureType = b'TxtT'
Threshold = b'Thsh'
TileNumber = b'TlNm'
TileOffset = b'TlOf'
TileSize = b'TlSz'
Title = b'Ttl '
To = b'T '
ToBuiltin = b'TBl '
ToLinked = b'ToLk'
ToMode = b'TMd '
ToggleOthers = b'TglO'
Tolerance = b'Tlrn'
Top = b'Top '
TotalLimit = b'TtlL'
Tracking = b'Trck'
TransferFunction = b'TrnF'
TransferSpec = b'TrnS'
Transparency = b'Trns'
TransparencyGrid = b'TrnG'
TransparencyGridColors = b'TrnC'
TransparencyGridSize = b'TrnG'
TransparencyPrefs = b'TrnP'
TransparencyShape = b'TrnS'
TransparentIndex = b'TrnI'
TransparentWhites = b'TrnW'
Twist = b'Twst'
okay breathe ๐ธ U's and V's, coming right up:
Type = b'Type'
UCA = b'UC '
URL = b'URL '
UndefinedArea = b'UndA'
Underline = b'Undl'
UnitsPrefs = b'UntP'
Untitled = b'Untl'
UpperY = b'UppY'
Urgency = b'Urgn'
UseAccurateScreens = b'AcrS'
UseAdditionalPlugins = b'AdPl'
UseCacheForHistograms = b'UsCc'
UseCurves = b'UsCr'
UseDefault = b'UsDf'
UseGlobalAngle = b'uglg'
UseICCProfile = b'UsIC'
UseMask = b'UsMs'
UserMaskEnabled = b'UsrM'
UserMaskLinked = b'Usrs'
Using = b'Usng'
Value = b'Vl '
Variance = b'Vrnc'
Vector0 = b'Vct0'
Vector1 = b'Vct1'
VectorColor = b'VctC'
VersionFix = b'VrsF'
VersionMajor = b'VrsM'
VersionMinor = b'VrsN'
Vertical = b'Vrtc'
VerticalScale = b'VrtS'
VideoAlpha = b'Vdlp'
Visible = b'Vsbl'
and the finale of this whole table ๐ lowercase, uppercase, numbers, an underscore โ she has range:
WatchSuspension = b'WtcS'
Watermark = b'watr'
WaveType = b'Wvtp'
WavelengthMax = b'WLMx'
WavelengthMin = b'WLMn'
WebdavPrefs = b'WbdP'
WetEdges = b'Wtdg'
What = b'What'
WhiteClip = b'WhtC'
WhiteIntensity = b'WhtI'
WhiteIsHigh = b'WhHi'
WhiteLevel = b'WhtL'
WhitePoint = b'WhtP'
WholePath = b'WhPt'
Width = b'Wdth'
WindMethod = b'WndM'
With = b'With'
WorkPath = b'WrPt'
WorkPathIndex = b'WrkP'
X = b'X '
Y = b'Y '
Yellow = b'Ylw '
ZigZagType = b'ZZTy'
_3DAntiAlias = b'Alis'
comp = b'comp'
and no, that last one is not a typo โ it genuinely is lowercase comp mapped to b'comp' ๐ slay.
โจ Type โจ
next up: class psd_tools.terminology.Type(*values) ๐ these are the type definitions, yanked straight out of PITerminology.h.
want the receipts? the page points you at https://www.adobe.com/devnet/photoshop/sdk.html.
and now, the list. A through C, bestie:
ActionData = b'ActD'
ActionReference = b'#Act'
AlignDistributeSelector = b'ADSt'
Alignment = b'Alg '
Amount = b'Amnt'
AntiAlias = b'Annt'
AreaSelector = b'ArSl'
AssumeOptions = b'AssO'
BevelEmbossStampStyle = b'BESs'
BevelEmbossStyle = b'BESl'
BitDepth = b'BtDp'
BlackGeneration = b'BlcG'
BlendMode = b'BlnM'
BlurMethod = b'BlrM'
BlurQuality = b'BlrQ'
BrushType = b'BrsT'
BuiltInContour = b'BltC'
BuiltinProfile = b'BltP'
CMYKSetupEngine = b'CMYE'
Calculation = b'Clcn'
Channel = b'Chnl'
ChannelReference = b'#ChR'
CheckerboardSize = b'Chck'
ClassColor = b'#Clr'
ClassElement = b'#ClE'
ClassExport = b'#Cle'
ClassFormat = b'#ClF'
ClassHueSatHueSatV2 = b'#HsV'
ClassImport = b'#ClI'
ClassMode = b'#ClM'
ClassStringFormat = b'#ClS'
ClassTextExport = b'#CTE'
ClassTextImport = b'#ClT'
Color = b'Clr '
ColorChannel = b'#ClC'
ColorPalette = b'ClrP'
ColorSpace = b'ClrS'
ColorStopType = b'Clry'
Colors = b'Clrs'
Compensation = b'Cmpn'
ContourEdge = b'CntE'
Convert = b'Cnvr'
CorrectionMethod = b'CrcM'
CursorKind = b'CrsK'
D through I, keep going, you're iconic:
DCS = b'DCS '
DeepDepth = b'DpDp'
Depth = b'Dpth'
DiffuseMode = b'DfsM'
Direction = b'Drct'
DisplacementMap = b'DspM'
Distribution = b'Dstr'
Dither = b'Dthr'
DitherQuality = b'Dthq'
DocumentReference = b'#DcR'
EPSPreview = b'EPSP'
ElementReference = b'#ElR'
Encoding = b'Encd'
EraserKind = b'ErsK'
ExtrudeRandom = b'ExtR'
ExtrudeType = b'ExtT'
EyeDropperSample = b'EyDp'
FPXCompress = b'FxCm'
Fill = b'Fl '
FillColor = b'FlCl'
FillContents = b'FlCn'
FillMode = b'FlMd'
ForcedColors = b'FrcC'
FrameFill = b'FrFl'
FrameStyle = b'FStl'
GIFColorFileType = b'GFPT'
GIFPaletteType = b'GFPL'
GIFRequiredColorSpaceType = b'GFCS'
GIFRowOrderType = b'GFIT'
GlobalClass = b'GlbC'
GlobalObject = b'GlbO'
GradientForm = b'GrdF'
GradientType = b'GrdT'
GrainType = b'Grnt'
GrayBehavior = b'GrBh'
GuideGridColor = b'GdGr'
GuideGridStyle = b'GdGS'
HistoryStateSource = b'HstS'
HorizontalLocation = b'HrzL'
ImageReference = b'#ImR'
InnerGlowSource = b'IGSr'
IntegerChannel = b'#inC'
Intent = b'Inte'
InterlaceCreateType = b'IntC'
InterlaceEliminateType = b'IntE'
Interpolation = b'Intp'
K through R, halfway, no cap:
Kelvin = b'Klvn'
KelvinCustomWhitePoint = b'#Klv'
Lens = b'Lns '
LightDirection = b'LghD'
LightPosition = b'LghP'
LightType = b'LghT'
LocationReference = b'#Lct'
MaskIndicator = b'MskI'
MatteColor = b'MttC'
MatteTechnique = b'BETE'
MenuItem = b'MnIt'
Method = b'Mthd'
MezzotintType = b'MztT'
Mode = b'Md '
Notify = b'Ntfy'
Object = b'Objc'
ObjectReference = b'obj '
OnOff = b'OnOf'
Ordinal = b'Ordn'
Orientation = b'Ornt'
PNGFilter = b'PNGf'
PNGInterlaceType = b'PGIT'
PagePosition = b'PgPs'
PathKind = b'PthK'
PathReference = b'#PtR'
Phosphors = b'Phsp'
PhosphorsCustomPhosphors = b'#Phs'
PickerKind = b'PckK'
PixelPaintSize = b'PPSz'
Platform = b'Pltf'
Preview = b'Prvw'
PreviewCMYK = b'Prvt'
ProfileMismatch = b'PrfM'
PurgeItem = b'PrgI'
QuadCenterState = b'QCSt'
Quality = b'Qlty'
QueryState = b'QurS'
RGBSetupSource = b'RGBS'
RawData = b'tdta'
RippleSize = b'RplS'
RulerUnits = b'RlrU'
S through Z, the final block of this class ๐ฆ:
ScreenType = b'ScrT'
Shape = b'Shp '
SmartBlurMode = b'SmBM'
SmartBlurQuality = b'SmBQ'
SourceMode = b'Cndn'
SpherizeMode = b'SphM'
State = b'Stte'
StringChannel = b'#sth'
StringClassFormat = b'#StC'
StringCompensation = b'#Stm'
StringFSS = b'#Stf'
StringInteger = b'#StI'
StrokeDirection = b'StrD'
StrokeLocation = b'StrL'
TextureType = b'TxtT'
TransparencyGridColors = b'Trnl'
TransparencyGridSize = b'TrnG'
TypeClassModeOrClassMode = b'#TyM'
UndefinedArea = b'UndA'
UnitFloat = b'UntF'
Urgency = b'Urgn'
UserMaskOptions = b'UsrM'
ValueList = b'VlLs'
VerticalLocation = b'VrtL'
WaveType = b'Wvtp'
WindMethod = b'WndM'
YesNo = b'YsN '
ZigZagType = b'ZZTy'
ate. and left no crumbs. โจ
๐ Unit ๐
and last but never least, class psd_tools.terminology.Unit(*values) ๐ โ the unit definitions, also pulled from PITerminology.h.
same receipts as above: https://www.adobe.com/devnet/photoshop/sdk.html.
all eight of them, tiny but mighty:
Angle = b'#Ang'
Density = b'#Rsl'
Distance = b'#Rlt'
Millimeters = b'#Mlm'
Percent = b'#Prc'
Pixels = b'#Pxl'
Points = b'#Pnt'
_None = b'#Nne'
look at her, a whole eight-item bop ๐
๐ INDICES AND TABLES ๐
the little navigation corner of the page, lowkey the most useful part for finding things:
Index <>Module Index <>Search Page <>
go click around, bestie, that's what they're for ๐
๐ Author ๐
Kota Yamaguchi โ the icon who wrote all of this. we love her, we thank her, we say her name with our chest ๐ซถ
๐ Copyright ๐
2019, Kota Yamaguchi โ that's the copyright line, right there, preserved forever, periodt.
and that's a wrap on SRC(1), bestie!! ๐ this page is version 1.17.4, dated Jun 25, 2026, and you read the WHOLE thing, every last constant and every last b'...' ๐ genuinely iconic behaviour. go drink some water, you've earned it ๐ธโจ๐
๐ฆ where this page comes from
- ubuntu stonking: python3-psd-tools 1.17.4+dfsg.1-1
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms