GithubHelp home page GithubHelp logo

chinedufn / psd Goto Github PK

View Code? Open in Web Editor NEW
261.0 5.0 35.0 3.51 MB

A Rust API for parsing and working with PSD files.

Home Page: https://chinedufn.github.io/psd

License: Apache License 2.0

Rust 100.00%

psd's Introduction

psd

Build status docs

A Rust API for parsing and working with PSD files.

Live Demo

The psd crate can be compiled to WebAssembly and used in a browser.

In the live demo you can visualize a PSD in the browser, toggle layers on and off and drag and drop a new PSD into the demo.

Demo screenshot

Check out the examples/drag-drop-browser directory for instructions on running the demo locally.

The Psd Book

The WIP The Psd Book will contain information about getting started with the psd crate, a description of the architecture and information on how to get started.

API Docs

Check out the API documentation to see everything that you can currently access.

Background / Initial Motivation

I'm working on a game and part of my asset compilation process was a script that did the following:

  1. Iterate over all PSD files

  2. Export every PSD into a PNG, ignoring any layers that begin with an _

  3. Combine PNGs into a texture atlas

For a couple of years I was using imagemagick to power step 2, but after getting a new laptop and upgrading imagemagick versions it stopped working.

After a bit of Googling I couldn't land on a solution for my problem so I decided to make this crate.

My approach was to support as much of the PSD spec as I needed, so there might be bits of information that you'd like to make use of that aren't currently supported.

That said, if there's anything missing that you need please feel very free to open an issue!

Usage

use psd::{ColorMode, Psd, PsdChannelCompression};

fn main () {
    // .. Get a byte slice of PSD file data somehow ..
    let psd = include_bytes!("./my-psd-file.psd");

    let psd = Psd::from_bytes(psd).unwrap();

    assert_eq!(psd.color_mode(), ColorMode::Rgb);

    // For this PSD the final combined image is RleCompressed
    assert_eq!(psd.compression(), &PsdChannelCompression::RleCompressed);

    assert_eq!(psd.width(), 500);
    assert_eq!(psd.height(), 500);

    // Get the combined final image for the PSD.
    let final_image: Vec<u8> = psd.rgba();

    for layer in psd.layers().iter() {
        let name = layer.name();

        let pixels: Vec<u8> = layer.rgba().unwrap();
    }

    let green_layer = psd.layer_by_name("Green Layer").unwrap();

    // In this layer the red channel is uncompressed
    assert_eq!(green_layer.compression(&PsdChannelKind::Red).unwrap(), PsdChannelCompression::RawData);

    // In this layer the green channel is RLE compressed
    assert_eq!(green_layer.compression(&PsdChannelKind::Green).unwrap(), PsdChannelCompression::RleCompressed);

    // Combine the PSD layers top to bottom, ignoring any layers that begin with an `_`
    let pixels: Vec<u8> = psd.flatten_layers_rgba(&|(_idx, layer)| {
        !layer.name().starts_with("_")
    }).unwrap();
}

See Also

License

MIT

psd's People

Contributors

chinedufn avatar firelightflagboy avatar gyk avatar katopz avatar kevzettler avatar kstasik-legion avatar lahickey avatar ok-nick avatar paolobarbolini avatar scoiatael avatar tdakkota avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

psd's Issues

Support PSB files

It is going to be a more common use case with a lot of photoshop end use cases relying on

Wrong transparency

Hi, thanks for the crate!

I'm trying to load a simple psd file with a few transparent layers, but I'm getting these weird white stripes all over the layer.

psd__load_glich

Any ideas why? Maybe you could point me to the right direction to look up.

Unicode string may have no paddings

I have a PSD file where the unicode string inside luni additional layer info has neither null bytes nor paddings:

38 42 49 4D 6C 75 6E 69 00 00 00 06 00 00 00 01 00 31    8BIMluni.........1

However, the current implementation decodes it as a unicode string with a padding length of 4: https://github.com/chinedufn/psd/blob/master/src/sections/layer_and_mask_information_section/mod.rs#L424, so all the parsed data after it are messed up.

It seems unicode string may or may not have paddings, depending on the section length and the absolute position of file cursor. References:

Just seeking to beginning_position + additional_layer_info_len seems to be the easiest solution.

Error: Index out of bounds

Hi!

Encountering a bug when attempting to load the pixels of each layer in a PSD.

Snippet

let file = fs::File::open(psd_path).expect("file should open read only");

let mut reader = BufReader::new(file);
let mut buffer = Vec::new();

reader.read_to_end(&mut buffer).unwrap();

let psd = Psd::from_bytes(buffer.as_slice()).unwrap();

for layer in psd.layers().iter() {
    let name = layer.name();

    let skip_file = Regex::new(r"^_.*").unwrap();
    if !skip_file.is_match(name) {
        println!("{:?}", name);

        let pixels: Vec<u8> = layer.rgba();
    }
}

Error

thread 'main' panicked at 'index out of bounds: the len is 16384 but the index is 16472', /home/gregl83/.cargo/registry/src/github.com-1ecc6299db9ec823/psd-0.2.0/src/psd_channel.rs:126:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Untested Presumption
Layer size can be larger than a PSD project size (dimensions) resulting in overflowed pixels in the PSD overflowing the rgba pixel vector.

How to obtain the tree structure data of layers?

I wish to obtain the layer structure and format it into JSON, structured as follows:

[
    {
        "type": "group",
        "visible": true,
        "opacity": 1,
        "blendingMode": "normal",
        "name": "group test",
        "left": 0,
        "right": 0,
        "top": 0,
        "bottom": 0,
        "height": 0,
        "width": 0,
        "children": [
            {
                "type": "layer",
                "visible": true,
                "opacity": 1,
                "blendingMode": "normal",
                "name": "layer test",
                "left": 0,
                "right": 0,
                "top": 0,
                "bottom": 0,
                "height": 0,
                "width": 0,
                "mask": {},
                "image": {}
            }
            
        ]
    }
]

Can anyone tell me how to do this?

Remove failure dependency

It's our only dependency and there aren't enough errors to be worth pulling in syn - so we should move to some hand written error impls

Layers outside of the bounding rect of the PSD

I am trying to render PSD layers to seperate PNG files for a game.
Our artists sometimes give us PSDs with layers that are slightly outside of the bounding box, as to make the final composition work. However, I would assume I can still extract the full image information.

This issue is likely related to or a duplicate of #26

Let me know if the general fix for this is similar as you outlined in #26 @chinedufn & i'll get to it!

When exporting the layers I get the following error:

thread 'main' panicked at 'attempt to multiply with overflow', /Users/bram/Development/psd/src/sections/layer_and_mask_information_section/layer.rs:438:9

or

thread 'main' panicked at 'index out of bounds: the len is 40212480 but the index is 40213160', /Users/bram/Development/psd/src/psd_channel.rs:171:21

Support text layers

I'm trying to access the text data (font/text) from a text layer. Is this currently possible or is it possible to support?

Layer visibility is opposite

According to the webtoon's implementation here, in adobe's specification actually 1 means hidden and 0 means visible. In this repository it's defined opposite.

I've also tested with some psd files, it also turns out that webtoon's approach was right.

Writing down PSD files

In https://github.com/kvark/vange-rs project, we faced an unexpected problem. We wanted to export the level data for modders to play with, and then import back. The data of the level is somewhat strange:

  • it has 3 byte channels and 2 half-byte (4-bit) channels
  • resolutions are like 16K by 2K

Apparently, there is no existing open format to support that. We tried TIFF and faced the lack of proper support on both GIMP and Photoshop sides. It would be very convenient if we could export/import a PSD (without losing the data) for this - at least Photoshop would be guaranteed to work.

layer name doesn't support Chinese characters

  // Read the layer name
    let name_len = cursor.read_u8()?; 
    let name = cursor.read(name_len as u32)?;
    let name = String::from_utf8_lossy(name);
    let name = name.to_string();

圆角矩形 1 in psd turns out to be Բ�Ǿ��� 1
name_len: 10
byte: [212, 178, 189, 199, 190, 216, 208, 206, 32, 49]

plz check out

No Timeline information

The current version of this crate does not support Timeline data, which would make it a valuable tool for animation. It would allow for batch exporting of animation frames, saving time and effort for games with a lot of frame-by-frame animations. The PSD file specifications indicate that Timeline information is stored at resource ID 0x0433, but it does not provide instructions on how to interpret this data. It probably wouldn't be too hard to do so.

Get layer of sub-sub-sub...-groups

Hi! Thank you for great crate!

I have a psd file which has nested layer groups(group in group).

Is there any change to get sub-groups of a group?

List of supported features

Hey fellas, thanks for making this library. I am currently using the "psd_tools" library for Python, but was considering rewriting this tool I've made in Rust. However I'm pretty sure this library is not nearly as complete as that one. Do you have a list of supported/unsupported features?

My requirement is just the ability to "merge" (composite) a layer group into a single image, with respect to the following features:

  • Adjustment Layers
  • Blending Modes
  • Clipping Masks
  • Masks

Is this currently possible? Would be happy to help but I am unfortunately not a Rust expert. I will say, the psd_tools library may be a good resource for you all for reference.

Remove thiserror after API stabilizes

thiserror is very convenient, but for this library it isn't worth pulling in syn or any other dependencies.

After the API stabilizes we should remove thiserror in favor of some hand maintained errors.

Related to #9

index out of bounds

Hi,
I'm trying to convert my PSD image to PNG, and when using psd.rgba()
I always get the same error

thread 'tokio-runtime-worker' panicked at xxx\psd-0.3.5\src\psd_channel.rs:130:29:
index out of bounds: the len is 96641024 but the index is 96641025

96641024 looks like a maximum value.
I tried a few other files and it seems the size cannot exceed a certain value, looking at my image size in Photoshop it is 6016*4016.

Here is my code:

let psd = Psd::from_bytes(std::fs::read(path).unwrap().as_bytes()).unwrap();
metadata.image_width = psd.width();
metadata.image_height = psd.height();
println!("{}*{}",metadata.image_width,metadata.image_height);

let final_image = psd.rgba();

what should I do :)

error[E0432]: unresolved import `virtual_node::DynClosure`

Maybe only me, I got this when try to build an example.

error[E0432]: unresolved import `virtual_node::DynClosure`
 --> /Users/katopz/.cargo/registry/src/github.com-1ecc6299db9ec823/virtual-dom-rs-0.6.14/src/dom_updater.rs:6:5
  |
6 | use virtual_node::DynClosure;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^ no `DynClosure` in the root

Any hint?

DescriptorStructure can occur inside an ImageResourcesBlock

Inside read_resource_block, some resource_ids like 3000 expect the value to be a Descriptor. I actually encountered this because when it is a Descriptor, I'm not sure what the deal is with data_len, but it is way off. This caused an Index out of bounds error, as it was trying to read the cursor way too far.

I tried to reverse engineer the binary, along with reading from the PSD file spec, but there's still just some bits in there I can't figure out, especially at the beginning with the data length.

I think something similar to what you're doing in read_slice_block could work, but I'm not quite sure how to set that up properly in read_resource_block

Cropping a layer based on it's content

I'm assuming this isn't currently supported and I was looking at a few dependencies that do, but they include a lot of other stuff outside of psd's scope.
I was planning on doing this externally, but would it cause further optimizations if done internally? Any pointers on how it could be done? My goal is to export a layer as a png, excluding any white space.
I'm currently using the layer.rgba() method

psd.group_by_id() expects vector index whereas group IDs range 1..n

Iterate Groups

for group in psd.groups().iter() {
    let group_id = group.id() as usize;
    // first group has value of 1
    
    let group = psd.group_by_id(group_id);
    // second group returned since vector index of 1 is second element
}

Get Group by ID

/// Get a group by id.
pub fn group_by_id(&self, id: usize) -> Option<&PsdGroup> {
    self.layer_and_mask_information_section
        .groups
        .item_by_idx(id)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.