Giter VIP home page Giter VIP logo

psd's Introduction

@webtoon/psd

Package on NPM Minified size

A lightweight Adobe Photoshop .psd/.psb file parser in typescript with zero-dependency for web browsers and NodeJS

@webtoon/psd is a fast, lightweight parser for Adobe Photoshop PSD/PSB files. It uses standard (ES2015+) features and can be used both in web browsers and in Node.js. It pulls in zero dependencies, making it smaller (~100 KiB minified) than other PSD parsers (ag-psd: 200 KiB, PSD.js: 443 KiB). It uses WebAssembly to speed up decoding image data.

Browser Support

Chrome Firefox Safari Edge Node
57 52 11 79 12

*Internet Explorer is not supported

Installation

$ npm install @webtoon/psd

Benchmarks

You can run benchmarks for @webtoon/psd in your browser.

Features

✅ Supported

  • Support large format (.psb)
  • Image / Layer information (size, offset, etc.)
  • Image / Layer pixel data
  • Unicode layer names
  • Image / Layer opacity
  • Text layers string value
  • Guides
  • Slices

🚧 Work in progress

  • Layer effects (shadow, overlays, etc.)

❌ Unsupported

  • Photoshop metadata not directly related to the image

Usage

@webtoon/psd is provided as a pure ECMAScript module.

Web Browsers

Check out the live demo (source code) for web browser.

@webtoon/psd must be bundled with a bundler such as Webpack or Rollup.

@webtoon/psd reads a PSD file as an ArrayBuffer. You can use FileReader or File to load a PSD file:

import Psd from "@webtoon/psd";

const inputEl: HTMLInputElement = document.querySelector("input[type='file']");
inputEl.addEventListener("change", async () => {
  const file = inputEl.files[0];

  const result = await file.arrayBuffer();
  const psdFile = Psd.parse(result);

  const canvasElement = document.createElement("canvas");
  const context = canvasElement.getContext("2d");
  const compositeBuffer = await psdFile.composite();
  const imageData = new ImageData(
    compositeBuffer,
    psdFile.width,
    psdFile.height
  );

  canvasElement.width = psdFile.width;
  canvasElement.height = psdFile.height;

  context.putImageData(imageData, 0, 0);
  document.body.append(canvasElement);
});

For performance, we recommend parsing PSD files in a Web Worker rather than the main thread.

NodeJS

Check out the source code for the Node.js example for web browser.

@webtoon/psd does not support the Node.js Buffer. You must explicitly supply the underlying ArrayBuffer.

import * as fs from "fs";
import Psd from "@webtoon/psd";

const psdData = fs.readFileSync("./my-file.psd");
// Pass the ArrayBuffer instance inside the Buffer
const psdFile = Psd.parse(psdData.buffer);

Since @webtoon/psd is provided as an ES module, you must use dynamic import() or a bundler to run it in CommonJS code:

const Psd = await import("@webtoon/psd");

API Docs

This library provides the Psd class as the default export.

Opening a file

Psd.parse(ArrayBuffer) takes an ArrayBuffer containing a PSD or PSB file and returns a new Psd object.

const psdFile = Psd.parse(myBuffer);

Traversing layers

A Psd object contains a tree of Layer and Group (i.e. layer group) objects.

  • The Psd object provides a children property, which is an array of top-level Layers and Groups.
  • Each Group object provides a children property, which is an array of Layers and Groups that belong immediately under the current layer group.
  • Psd, Group, and Layer objects provide a type field, which can be used to discriminate each type:
import Psd, {Node} from "@webtoon/psd";

// Recursively traverse layers and layer groups
function traverseNode(node: Node) {
  if (node.type === "Layer") {
    // Do something with Layer
  } else if (node.type === "Group") {
    // Do something with Group
  } else if (node.type === "Psd") {
    // Do something with Psd
  } else {
    throw new Error("Invalid node type");
  }

  node.children?.forEach((child) => traverseNode(child));
}

traverseNode(psdFile);

The Psd object also provides the layers property, which is an array of all Layers in the image (including nested).

for (const layer of psdFile.layers) {
  doSomething(layer);
}

Decoding image data

Use Psd.prototype.composite() and Layer.prototype.composite() to decode the pixel information for the entire image or an individual layer.

Note that for Psd.prototype.composite() to work, PSD/PSB files need to be saved in "Maximize Compatibility" mode. Otherwise, it will return no data. You can enable it in Preferences > File Handling > File Compatibility > Maximize PSD and PSB File Compatibility

// Decode the pixel data of the entire image
pixelData = await psd.composite();

// Extract the pixel data of a layer, with all layer and layer group effects applied
// (currently, only the opacity is supported)
layerPixelData = await layer.composite();

// Extract the pixel data of a layer, with only the layer's own effects applied
layerPixelData = await layer.composite(true, false);

// Extract the pixel data of a layer, without any effects
layerPixelData = await layer.composite(false);

License

@webtoon/psd is released under the MIT license.

Copyright 2021-present NAVER WEBTOON

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

psd's People

Contributors

alexanderspevak avatar alexspevak avatar anwynaoki avatar arecsu avatar dlehdanakf avatar pastelmind avatar scoiatael avatar simdaesoo 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

psd's Issues

Help importing project into node js project

I'm attempting to import the library into a node js project and I'm getting some errors. I'm working on getting up to speed on all things node js but I am able to use other libraries using requires. I'm also using Typescript.

At the top of module, myclass.ts I have:
import Psd from "@webtoon/psd";

This generates this error:

[Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
require() of ES modules is not supported.
require() of /Users/project/node_modules/@webtoon/psd/dist/index.js from /Users/project/MyProjectClass.ts is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/project/node_modules/@webtoon/psd/package.json.

It doesn't make sense to me what to do with that information.

Update Text in Layer

its possible update a text in layer?
Example..
I have a layer with text "Hello World", I like the change to another text.

Its possible the make this using this lib?

Thanks.

layer style no parser

let nodeFX = node.get('objectEffects').data; 
// data is not defined is the node has no fx options.

This property contains all the informations from the FX (also called blending options) from Photoshop. (e.g. Drop Shadow, Inner Shadow ...).

{
    data: {
		ebbl: [Object] // Bevel and Emboss
		FrFX: [Object] // Stroke 
		IrSh: [Object] // Inner Shadow
		IrGl: [Object] // Inner Glow
		ChFX: [Object] // Satin
		SoFi: [Object] // Color Overlay
		GrFl: [Object] // Gradient Overlay
		patternFill: [Object] // Pattern Overlay
		OrGl: [Object] // Outer Glov
		DrSh: [Object] // Drop Shadow
    }
}

Expand test suite

It would be nice to expand our test suite and test our library more rigorously. I don't have a clear plan, so I'm open to suggestions.

Some ideas:

Opening file

  • Fail: Empty file
  • Fail: File is too large (>2GB)

File Header

  • Fail: File Header is too small/truncated
  • Fail: Normal file with invalid signature (not ‘8BPS’, e.g. ‘FAIL’)
  • Fail: Normal file with lowercase signature (‘8bps’)
  • Fail: Normal file with invalid version (not 1)
    • PSB uses version number 2
  • Fail: Reserved segment contains nonzero values
  • Fail: Number of channels exceeds max (>56)
  • Fail: Image height > 30000
    • PSB has image height limit of 300,000
  • Fail: Image width > 30000
    • PSB has image width limit of 300,000
  • Fail: Invalid bits per channel (not in { 1, 8, 16, 32 })
  • Fail: Invalid color mode (not in { 0, 1, 2, 3, 4, 7, 8, 9 })

Color Mode

  • Fail: Missing or truncated color mode section
  • Success: Non-(indexed (2) or duotone (8)) image has empty Color Mode section
  • Fail: Non-indexed/duotone image has non-empty Color Mode section
  • Fail: Indexed image has invalid color table size (not 768)
  • ???: Duotone images have undocumented format—do we want to handle this?
    • Other apps should ignore/preserve this section if the image is duotone

Resources

  • Fail: Missing or truncated resources section

Resource block

  • Fail: Resource block is too small/truncated
  • Fail: Resource block has invalid signature (not ‘8BIM’)
  • Fail: Resource block has lowercase signature (‘8bim’)
  • Fail: Resource block has duplicate ID
  • Fail: Resource block has unknown ID value
(see https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_38034 for list of valid IDs)
  • Fail: Resource block name string is invalid
  • Fail: Resource block name string is not padded with zero (should we even check this?)
  • Fail: Resource data section is invalid (need more info)

Layer and Mask

  • Fail: L&M is missing or truncated

Layer Info

  • Fail: Layer length is not a multiple of 2
  • Fail: Layer info section is missing or truncated
  • Fail: Layer records are bad
  • Fail: Channel image data is bad

Layer Record

  • Fail: Blend mode signature is invalid (not ‘8BIM’)
  • Fail: Blend mode key is unknown (see Layer records for the full list)
  • Fail: Clipping value is invalid
  • Fail: Bits 5~7 are nonzero (should we even check this?)
  • Fail: Filler is nonzero
Layer mask/adjustment layer data
  • Fail: Length is not one of 0, 20, 36
  • Fail: Default color is neither 0 or 255
  • Fail: Bits 5~7 are nonzero (should we even check this?)
Layer blending ranges
  • Fail: Section is missing or truncated
Channel Image Data
  • Fail: Invalid compression method (not one of 0, 1, 2, 3)
  • Fail: Image data is missing or truncated
Additional Layer Info
  • Fail: ALI section is missing or truncated
  • Fail: Unknown key (see

Global layer mask info

  • Fail: Section is missing or truncated
  • Fail: Length is too short (< 13)

Image Data

  • Fail: Invalid compression method
  • Fail: Missing or truncated compressed data
  • Fail: Compressed data does not match compression method

SourceMaps not working against minified content

Not sure why the code is not getting sourcemapped to TypeScript (unminified), I see the //#sourceMappingURL=index.js.map in the dist/index.js file, is this fixable? See my error from #100:

my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:397
    throw new Le();
          ^
          
Le
    at wt (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:397:11)
    at fn (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1188:76)
    at Rn (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1490:13)
    at Function.parse (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1982:15)
    at <anonymous> (my-app/tmp/psd.ts:162482:21)
    at Object.<anonymous> (my-app/tmp/psd.ts:162490:4)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Object.F (my-app/node_modules/.pnpm/@[email protected]/node_modules/@esbuild-kit/cjs-loader/dist/index.js:1:941)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)

Node.js v20.10.0

I am using Next.js, do I need to do anything fancy do you think, to get your sourcemaps?

How to save a layer to a image file

In the documentation it says you can export a layer to pixel data. How would you save that to a PNG? I'm using node js.

// Extract the pixel data of a layer, with all layer and layer group effects applied
var layerPixelData = await layer.composite();

Keep the document width and height , when exporting a layer (animations)

H!

Maybe someone can use this in the future.
I have made some animations inside photoshop, within the same document.
each layer is a frame, and have different sizes.

When you export the layer, then you get different sizes.
With this code, you will keep the document sizes, and the correct layer position in the document.
So you can replay the animation again, inside a game or whatever.

import * as fs from "fs"
import Psd from "@webtoon/psd"
import { createCanvas, createImageData } from 'canvas'

const psdData = fs.readFileSync("talk-sideways.psd")
const psdFile = Psd.parse(psdData.buffer)

    let layerPixelData = await layer.composite()

    const canvas = createCanvas(psdFile.width, psdFile.height)
    const ctx = canvas.getContext('2d')

    const image = createImageData(layerPixelData, layer.width, layer.height)
    ctx.putImageData(image, layer.left, layer.top)

    const out = fs.createWriteStream('out.png')
    const stream = canvas.createPNGStream()
    stream.pipe(out)
    out.on('finish', () => console.log('The PNG file was created.'))

Opening a PSD file throws "invalid typed array length" error

I'm trying to open a PSD file i haved created from Photopea into the demo and after selecting the file, the preview did not worked and instead the demo threw an error:

image

When dissecting the stack trace, it leads me to this code which is in line 253 254:
image

Hope it helps 😉 hoping to use it for a project

`FontCaps` not working?

I'm trying to know whether a text is capitalized.

I found the layer.layerFrame.layerProperties.textProperties.ResourceDict.StyleSheetSet.StyleSheetData.FontCaps property but it is always set to 0.
Whereas on Photoshop, the text is correctly set to capitalized:
image

Is there anyone who can help to point out where I can get the correct property to see if a text is capitalized or not? 😄

Retrieving mask data

Hi there, great project and the 🚀 is impressive!

I have one question related to masked layers. Basically, I would like to retrieve an image buffer for the mask data (similar to retrieving the composite of the Psd file or the Layer, as an Uint8ClampedArray).

However, it's not clear how to consume this data. I understand that I can retrieve the masks bounding box reading the layer.maskData Objects left, right, top, bottom values. I also see that there is an ArrayBuffer inside the layer.layerFrame.userMask.data Object.

However, the length of said buffer does not match with the size of the mask (as it expected to be width * height * 4 in length). I was thinking that this buffer contains the alpha channel or gray scale data only, however after converting this to fit in an RGBA sized buffer, the rendered data does not reflect the original masks shape, with pixels basically all over the place. I also noticed that the Layer class has an async method getUserMask|getRealUserMask which seems to return RGBA-sized values, but once more the rendered data does not reflect the masks shape.

As such, I'm not sure how to read and render the mask buffer object. Is there something obvious I'm overlooking with regards to the mask size ?

PNG converted to PSD with webtoon/psd not parseable with `Psd.parse(buffer)` (PSD generated from PNG with imagemagick-wasm)?

I created this PSD file.psd.zip from this PNG file.png.zip, using https://github.com/dlemstra/magick-wasm . That magick library (for the browser) works on converting PNG to JPG/etc., and I saved the bytes output from the selected browser file to a .psd file on my computer, and that is the contents of file.psd.zip. That psd seems to render on my Mac (and with CMD+space it shows large):

Screenshot 2024-01-23 at 12 17 38 PM

That png itself was generated from another png (I'm playing with magick-wasm), if that matters. But it renders as a PSD locally if I say the bytes to a .psd file, but I get this error in Psd.parse(arrayBuffer):

my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:397
    throw new Le();
          ^
          
Le
    at wt (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:397:11)
    at fn (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1188:76)
    at Rn (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1490:13)
    at Function.parse (my-app/node_modules/.pnpm/@[email protected]/node_modules/@webtoon/psd/dist/index.js:1982:15)
    at <anonymous> (my-app/tmp/psd.ts:162482:21)
    at Object.<anonymous> (my-app/tmp/psd.ts:162490:4)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Object.F (my-app/node_modules/.pnpm/@[email protected]/node_modules/@esbuild-kit/cjs-loader/dist/index.js:1:941)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)

Node.js v20.10.0

This is occurring whether or not I'm calling Psd.parse in Node.js or the browser. So it fails to parse the PSD, and so I can't render the PSD in the browser.

Any ideas what is wrong with this PNG, or why this isn't parsing?

I get the same error when trying to parse a JPEG as well, so not sure.

My messy code, with the PSD functionality temp hacked in for now:

useEffect(() => {
  if (!files?.length) {
    return
  }

  const file = files[0]
  setInput(file)
  // https://www.npmjs.com/package/wasm-imagemagick
  file.arrayBuffer().then(async data => {
    const ir = new FileReader()
    ir.onloadend = () => {
      setInputString(ir.result as string)
    }
    ir.readAsDataURL(file)
    if (data.byteLength <= bytes('16mb')) {
      if (outputFormat === 'psd') {
        const canvasElement = canvasRef.current
        if (canvasElement) {
          try {
            console.log(bufferToString(await file.arrayBuffer()))

            function bufferToString(buf: ArrayBuffer) {
              var view = new Uint8Array(buf)
              var array: Array<string> = []
              Array.prototype.forEach.call(view, item => {
                array.push(
                  '0x' +
                    (item as number).toString(16).padStart(2, '0'),
                )
              })
              return `[ ${array.join(',\n  ')} ]`
            }
            const psdFile = Psd.parse(await file.arrayBuffer())
            const context = canvasElement.getContext('2d')
            const compositeBuffer = await psdFile.composite()
            const imageData = new ImageData(
              compositeBuffer as Uint8ClampedArray,
              psdFile.width as number,
              psdFile.height as number,
            )
            setShowCanvas(true)

            canvasElement.width = psdFile.width
            canvasElement.height = psdFile.height

            context?.putImageData(imageData, 0, 0)
          } catch (e) {
            console.log(e)
          }
        }
      } else {
        readWithImageMagickCallback(
          new Uint8Array(data),
          (err, image) => {
            if (err) {
              console.log(err)
              return setInputError(err.message as string)
            } else if (image) {
              writeWithImageMagick(image, outputFormat)
                .then(out => {
                  setInputError(undefined)
                  const path = file.name.split('.')
                  if (path.length > 1) {
                    path.pop()
                  }
                  const blob = new Blob([out])
                  setOutput(blob)
                  setOutputFileName(
                    `${path.join('.')}.${outputFormat.toLowerCase()}`,
                  )
                  // downloadBlob(
                  //   blob,
                  //   `${path.join('.')}.${outputFormat.toLowerCase()}`,
                  // )

                  const or = new FileReader()
                  or.onloadend = () => {
                    setOutputString(or.result as string)
                  }
                  or.readAsDataURL(blob)
                })
                .catch(error => {
                  setInputError(error.message as string)
                })
            }
          },
        )
      }
    } else {
      setInputError(
        `File should be less than 16mb so it doesn't crash the browser.`,
      )
    }
  })
}, [files, outputFormat, canvasRef])

Can I programatically add image to the layer?

So instead of me going to photopea, uploading psd file, selecting layer, adding an image, resizing to fit the layer, exporting to png...
I would like to do this programatically in javascript (server side or client side). I want to write a function that accepts psd file, image file and options. It should output a .png file. Am I in the right place? Can I do this with "webtoon"? I've found libraries like "psd.js" but still not sure how can I achieve that. Can anyone give me an example? Your help is very much appreciated!

How can I check the LayerId?

I'm using the module very well.
Thank you for working on it.

How can I check the layerID?

I think there are GroupID and Regular-ID(?), but I don't have an LayerID to specify the layer.

Is there a way to check it out?

Please check.
Thank you.

Layer hide and unhide

Hello,

Is it possible to unhide a hidden layer. I have a psd file and I would like to hide and unhide options based on my confirmation file.

Thanks,

i have a question

sorry,when i use psd to get the font but i cannot get color of font

Proper instructions for contributions is needed

Firstly guide on how to install all the dependencies and run the project either in contribution.md or any other readme would help new contributors to onboard.

Secondly, guideline on what or how to contribute would be useful.

node composite error

hi
I'm trying to use this library at server.

When I try to composite psd files, atob reference error is occured.

Also when I change atob to buffer, below error is occured.
TypeError: WebAssembly.instantiate(): Import #0 module="./webtoon_psd_decoder_bg.js" error: module is not an object or functiom

How can I use composite?

Thankyou

Investigate if we need to implement ZIP compression support

Adobe's PSD file format document claims that there are four compression methods for image channels: uncompressed (0), RLE (1), ZIP (2), ZIP with prediction (3). However, I have yet to find a PSD file that uses compression methods 2 and 3. If they do exist, we may have to support them as well.

What to do

  • Attempt to find or obtain a PSD file that uses compression methods 2 and 3
  • Find other PSD parsers that support methods 2 or 3
  • Decide if we want to implement ZIP compression support

Prior art

Benchmark fails occasionally due to imageDecodeTime being negative

Benchmark for ag-psd occasionally fails with the following error: imageDecodeTime must be a nonnegative number

This is probably happening because of the rather fragile (and broken) way we currently use to measure the image decode time, i.e. by subtracting the parse time (measured separately) from the total render time:

imageDecodeTime:
parseAndImageRenderEnd - parseAndImageRenderBegin - parseTime,

The benchmark app is long overdue a rewrite anyway; I'm thinking of writing it in React.

Parse EngineData

We got an internal request regarding the "EngineData" field of the Type Tool Object Setting structure, which encodes information about a text layer.

The Type Tool Object Setting structure is part of the Additional Layer Information record, inside the Layer and Mask Information Section of a PSD file.

PSD
  Layer and Mask Information
    Layer Info
      Layer Records
        Additional Layer Information
          Type Tool Object Setting
            text data (Descriptor classId == "TxLr")
              EngineData

The EngineData field is encoded in an undocumented format (nicknamed "EngineData format") invented by Adobe. While @webtoon/psd does not currently parse this segment, we may have to do so in the future, in order to support additional features related to text layers.

Prior work

Several PSD parsers can handle the EngineData format:

However, we MAY want to write a custom parser in TypeScript, in accordance with the Zero-Dependency design goal (see #5).

Project goals

This is a discussion topic and a work in progress.

We should specify our project goals and/or principles to help us focus on the right things.

What goals?

Some suggestions based on our work so far:

  • Correctness
  • Minimal set of wanted features
  • Zero-dependency
  • Performance: improve speed, reduce memory footprint

Where?

Ideally, the project goals should be part of the documention, perhaps in a CONTRIBUTING.md file. We may also put them in the project wiki (currently not enabled).

Other

For now, we can link to this issue when we mention our project goals and/or principles.

Investigate passing to/from web workers

A task that parses a large PSD file can often exceed the 16ms budget in web browsers and block UI updates. To avoid this, it's natural to attempt parsing a PSD file in a Web Worker via postMessage() and sending the results back. It would be nice to support this use case.

Unfortunately, this is currently impossible because the Psd object cannot be reliably (de)serialized with the structured clone algorithm. Psd provides instance methods and getters, which are lost when passed to/from a Web Worker.

We have some ideas, but would still like feedback:

  1. Convert the Psd class (and other classes) into plain, structured clone-able objects
    • Instance methods will have to be converted to plain functions
    • This will be quite disruptive as it is backwards incompatible
  2. Create Psd.prototype.serialize() that generates a structured clone-able implementation, as well as Psd.deserialize() that reconstructs the original Psd object
    • This will be clunky and leak implementation details all over

Replace Smart Object with image in-browser

Hi there,
Can someone help me build this feature for a client,
I want a way to get all smart objects inside the psd, and then generate file inputs for each smart object, and when the user uploads an image, i want to display live changes

text layer's textProperties no parsed corretly

I try to get font style.but it parse result always same(in fact not).

The StyleSheetData like FontSize, FillColor,StrokeColor and other property are same,it seems like no parse yet?

image

Investigate providing both WebAssembly- and vanilla JS-based decoders

When we replaced the asm.js image decoder with a WebAssembly-based one (#20), we gained performance and resilience† at the expense of increased bundle size and breaking compatibility. This was fine for our use case--but what if people want to use our library in a runtime that does not support WebAssembly (or asm.js for that matter)? What if bundle size is critical?

asm.js is dead tech and there are development tools (e.g. esbuild) that do not support it. See #20 (comment)

In our internal experiments, a properly optimized vanilla JS decoder was ~15% slower in Chrome (V8), and ~50% slower in Firefox and Safari. Since Node.js uses V8, we may expect similar performance differences in Node.js. These differences may be acceptable to those who want a tiny bundle--or don't have the luxury of WebAssembly.

Perhaps we could provide two decoders (vanilla JS and WebAssembly) and let the user choose?

Brainstorming Strategies

Create separate bundles for vanilla JS and WebAssembly, possibly exposing them as separate endpoints:

import Psd from '@webtoon/psd'         // WebAssembly
import Psd from '@webtoon/psd/vanilla' // Vanilla JS

Create two parse() methods and export them:

import { parse, parseWithJs } from '@webtoon/psd'

const psd1 = parse(arrayBuffer)
psd1.composite() // WebAssembly

const psd2 = parseWithJs(arrayBuffer)
psd2.composite() // Vanilla JS

Create two composite() methods:

import { parse, composite, compositeWithJs } from '@webtoon/psd'

const psd = parse(arrayBuffer)
composite(psd)       // WebAssembly
compositeWithJs(psd) // Vanilla JS

how to recover color with hsb?

I have a problem when the color have hsb attribute like that.

image

image

top is export by photoshop, bottom is by @webtoon/psd. color is grayer than designed.

is there any good way to solve it, thanks.

ICC profile

One of features available in psd-tools is ICC profile handling.

This is done by extracting relevant tag and then converting image data after extraction.

This in turns uses Python bindings for littlecms (https://pypi.org/project/littlecms/). In our case this won't fly - closest thing I was able to find are low-level binding based on emscripten.

So the questions are:

  • should this library handle the conversion or only expose information for ICC (and let users worry about converting themselves)? If former, is importing emscripten littlecms an ok solution? I'd rather create bindings ourselves than import npm library of dubious quality.
  • can I start working on it? :) I suppose the first step would be to look into alternative libraries for conversion.

upload psd parse error

image
image

image

I uploaded a psd file and reported an error when parsing. The error screenshot is shown above. After I open the source code to modify the code and recompile, it can be used normally. The location of the modified source code is as follows
image

Here is my psd file

test_psd.zip

Investigate tools for build orchestration in monorepo

Currently, packages in our monorepo have the following dependency graph:

psd-decoder psd <-- benchmark, example-browser, example-node, benchmark

When building a package, we must ensure that its dependencies are built first, and in order. Furthermore, when building a package in watch mode, we must launch watchers for the dependencies as well. Managing this with NPM scripts is tricky and error-prone, and I already had to push fixes such as #26 and #27.

List of tools

* npm-run-all has been abandoned for some time. npm-run-all2 seems to be the most well-maintained fork.
† Since version 5, Lerna bundles and is powered by Nx, so there's little point in installing it for new projects--we should use Nx directly.

visible always true ?

Hi 👋 I'm trying to get information from .psb about whether the layer is disabled or not, for some reason I always get true, is this normal?
2022-04-26_03-38
2022-04-26_03-39
or am I looking somewhere wrong ?

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.