...now do the same thing with Photoshop

After a short interlude working on infrastructure, I was once again tasked with writing a parser. This time with Photoshop, and pretty much like before we had one working in Python. This time though using a Python-WASM interpreter like pyodide was an option - since it was a pure library, with no CPython or OS-level requirements. Sadly after benchmarking, it turned out that it was not an option - it was simply too slow.

Finding the right solution

Similar to Illustrator case I benchmarked every solution I could find, in any language that was browser-compatible. This time there were many more that met the basic criteria: meltingice/psd.js, chindefun/psd] and webtoon/psd.

psd.js worked for most files and had (almost) all the features we needed. But that almost was the part that I didn’t like - it was written fully in CoffeeScript, meaning making small modifications was quite hard. I argued against it after coding some changes - in certain cases, I needed to read the Ruby counterpart to fully understand the code I was looking at.

That meant one of the less feature-full libraries: in either Rust or Typescript. Both had good code quality - I even made some improvements in my spare time: https://github.com/chinedufn/psd/pull/35, https://github.com/chinedufn/psd/pull/36 and I loved the feeling of the type-checker working for me, not against.

The only problem with Rust one was the amount of missing features - and Rust itself. After some discussions with the team, we agreed to give webtoon/psd a go.

Making it work

That meant implementing some smaller features and making a Pull Request to see whether they were open to cooperation. I volunteered to implement a new feature on https://github.com/webtoon/psd/issues/6 and did so in https://github.com/webtoon/psd/pull/43 after getting confirmation that it’s ok.

In total, I added a handful of features to the library over multiple PRs - both in Typescript and Rust. I had the advantage of our private code, which meant I had inside knowledge of the parsing details and could just translate it from Python to the respective language.

One aspect that didn’t translate well was ICC profile handling. Turns out every implementation I could find on the internet used the same library underneath - LittleCMS. It’s a C library, so the only option for including it was to have a WASM build. Turned out this weighs around 400KB, making it too big for inclusion in webtoon/psd. So the solution was to split the code: have simple profile extraction upstream and release a small utility to do the colour correction as a separate library (https://github.com/opendesigndev/image-icc-profile-converter). The whole endeavour is described in https://github.com/webtoon/psd/issues/46.

As usual, the next step after having a working parser was to integrate it with the rest of our stack. During this process, we discovered another set of missing features - quite a lot in fact: https://github.com/webtoon/psd/pull/74. We implemented them first on our fork (one by one) and then created a huge Pull Request to upstream them. In the meantime, we pushed our fork to npm: https://www.npmjs.com/package/@opendesign/psd-ts and made it a dependency of OpenDesign. Once PR is merged, we can switch back to upstream.

Sadly soon afterwards I got re-assigned to another team, meaning the future of OpenDesign is out of my hands.


Tags: rust ceros backend typescript wasm


Copyright © 2025 L Czaplinski
Powered by Cryogen
Theme by KingMob