ag-psd
Read and write Adobe Photoshop (.psd / .psb) files in pure Rust, with no
native Photoshop or system dependencies.
This crate is a from-scratch Rust port of the excellent
ag-psd TypeScript library by
Agamnentzar. The public data model deliberately mirrors the upstream library, so
the structures (Psd, Layer, ReadOptions, WriteOptions, …) will feel
familiar if you've used the JavaScript version.
🤖 This is a vibe-coded port
The overwhelming majority of this code was written by Claude (Anthropic), driven from the original TypeScript source as the specification and the upstream test fixtures as the oracle. It is used in production in a manhwa typesetting tool (PSD export of source / clean / editable text layers), but it has not been hand-audited line by line. Treat it accordingly: it is well tested against real fixtures, but it is not a battle-hardened, human-reviewed codebase. Bug reports and PRs are very welcome.
Features
- Read PSD/PSB documents into a rich, typed object model.
- Write PSD/PSB documents from that same model (round-trippable).
- Layers & groups — nested layer trees, names, opacity, blend modes, bounds, visibility, clipping, layer masks.
- Pixel data — composite image and per-layer RGBA pixels, with PackBits/RLE and ZIP compression supported on read and write.
- Text layers — editable type layers, including the Engine Data text engine blob (font, size, alignment, paragraph/character styles) and the type-tool transform matrix.
- Layer effects — drop shadow, stroke, glow, overlays, bevel, etc.
- Vector / shape data, adjustment layers, smart-object metadata, image resources, annotations, artboards, global layer mask info.
- Companion Adobe formats, ported alongside the core library:
.abr— Photoshop brushes (read).csh— custom shapes (read/write).ase— Adobe Swatch Exchange palettes (read/write)- Engine Data parser/serializer (text engine)
Installation
[]
= "0.1"
Requires Rust 1.85+ (the crate uses the 2024 edition). The only runtime
dependency is flate2 for ZIP-compressed
channel data.
Quick start
use ;
use ;
For building documents from scratch, reading pixels, creating text layers, and a
full tour of the options, see docs/usage.md.
Public API at a glance
The crate root re-exports the main entry points:
| Symbol | Purpose |
|---|---|
read_psd(&[u8], &ReadOptions) -> Result<Psd, ReadError> |
Parse a PSD/PSB from memory |
write_psd(&Psd, &WriteOptions) -> Vec<u8> |
Serialize a PSD/PSB to bytes |
write_psd_to_writer(&mut PsdWriter, &Psd, &WriteOptions) |
Serialize into an existing writer |
read_abr, read_csh / write_csh, read_ase / write_ase |
Companion Adobe formats |
parse_engine_data, serialize_engine_data, decode_engine_data2 |
Text Engine Data |
The document model itself lives in the [ag_psd::psd] module: Psd, Layer,
LayerAdditionalInfo, PixelData, BlendMode, ColorMode, ReadOptions,
WriteOptions, and the many supporting types.
Status & limitations
The bulk of the upstream library is ported and exercised against the original test fixtures:
- Reads essentially all of the upstream read fixtures.
- Round-trips (read → write → read) the large majority of fixtures with a structurally stable result.
The writer intentionally inherits the same constraints as upstream ag-psd:
- Writing is 8-bit RGB only. 16/32-bit, grayscale, indexed, bitmap and duotone documents can be read, but are not re-emitted in their original depth/mode. This matches upstream behavior and is the reason a handful of fixtures do not byte-round-trip.
- CMYK documents are rejected at the header on read.
Known partial / stubbed areas (not required for the typesetting use case that drove the port, but relevant if you need "100% complete"):
- Vector gradient/pattern content (
Grad/Ptrn),vstkstroke units,vogk/pthspath lists. Lr16/Lr32nested layers,Psd.linked_filesstorage, the smart-objectSoLdfilter-FX subtree,shmdtimeline/comps.- Thumbnail generation on write, link-group resources,
Txt2text-path restoration.
If you hit one of these, please open an issue — they are tracked and can be filled in on demand.
Testing
A fixture harness (tests/fixtures.rs) additionally reads and round-trips the
upstream ag-psd .psd fixtures when they are available on disk; it reports
coverage rather than asserting byte-exactness.
Credits & license
- Ported from
ag-psdby Agamnentzar. - Original PSD format reverse-engineering and structure courtesy of the upstream project and the Adobe Photoshop File Format specification.
- Rust port: vibe-coded by Claude (Anthropic), maintained by Vasyanator.
Licensed under the MIT License, the same as upstream. The original
copyright © 2016 Agamnentzar is preserved; see LICENSE.