meltingice / psd.js

A Photoshop PSD file parser for NodeJS and browsers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

toPng collapse when psd include large image

xty1992a opened this issue · comments

Hello

I have some psd file, and I need export some image from it.
my code like this

PSD.open(root("data/psd/1/地产20.psd"))
  .then(async (psd) => {
    const tree = psd.tree();
    const children = tree.children();
    const big = children.find((it) => it.name === "313682976"); // some image 5406 * 6235
    console.log(big.layer.image);
    return big.layer.image.saveAsPng(root("output.png")); // collapse
  })
  .then(() => {
    console.log("Finished!");
  })
  .catch((e) => {
    console.log("error", e.message);
  });

and the layder.image be like this

Layder.image
LazyExecute {
  obj: ChannelImage {
    layer: Layer {
      file: [File],
      header: [Header],
      mask: [Mask],
      blendingRanges: [Object],
      adjustments: [Object],
      channelsInfo: [Array],
      blendMode: [BlendMode],
      groupLayer: null,
      infoKeys: [Array],
      top: -637,
      left: -1046,
      bottom: 5598,
      right: 4360,
      channels: 4,
      height: 6235,
      rows: 6235,
      width: 5406,
      cols: 5406,
      opacity: 255,
      visible: true,
      clipped: false,
      layerEnd: 36230,
      legacyName: '313682976',
      objectEffects: [Function],
      layerNameSource: [Function],
      layerId: [Function],
      blendClippingElements: [Function],
      blendInteriorElements: [Function],
      locked: [Function],
      metadata: [Function],
      image: [Circular],
      node: [Layer]
    },
    _width: 5406,
    _height: 6235,
    file: File {
      data: <Buffer 38 42 50 53 00 01 00 00 00 00 00 00 00 03 00 00 14 c3 00 00 0d d7 00 08 00 03 00 00 00 00 00 00 83 7c 38 42 49 4d 04 04 00 00 00 00 01 3f 1c 01 5a 00 ... 73510973 more bytes>,
      pos: 52147406
    },
    header: Header {
      file: [File],
      sig: '8BPS',
      version: 1,
      channels: 3,
      rows: 5315,
      cols: 3543,
      depth: 8,
      mode: 3
    },
    numPixels: 33706410,
    length: 134825640,
    channelLength: 33706410,
    pixelData: [],
    channelData: [],
    opacity: 1,
    hasMask: false,
    startPos: 16114209,
    endPos: 150939849,
    channelsInfo: [ [Object], [Object], [Object], [Object] ],
    maskData: []
  },
  file: File {
    data: <Buffer 38 42 50 53 00 01 00 00 00 00 00 00 00 03 00 00 14 c3 00 00 0d d7 00 08 00 03 00 00 00 00 00 00 83 7c 38 42 49 4d 04 04 00 00 00 00 01 3f 1c 01 5a 00 ... 73510973 more bytes>,
    pos: 52147406
  },
  startPos: 16114209,
  loaded: false,
  loadMethod: 'parse',
  loadArgs: [],
  passthru: []
}

then I got message like this

collapse message
<--- Last few GCs --->

[13840:000001FD3F55A360]     6818 ms: Scavenge 1040.1 (1058.2) -> 1031.7 (1061.9) MB, 3.9 / 0.0 ms  (average mu = 0.848, current mu = 0.942) allocation failure
[13840:000001FD3F55A360]     6826 ms: Scavenge 1043.6 (1061.9) -> 1035.3 (1065.2) MB, 3.8 / 0.0 ms  (average mu = 0.848, current mu = 0.942) allocation failure
[13840:000001FD3F55A360]     6835 ms: Scavenge 1047.1 (1065.2) -> 1038.9 (1068.7) MB, 4.0 / 0.0 ms  (average mu = 0.848, current mu = 0.942) allocation failure


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 00007FF71FBDABBD]
Security context: 0x0105560c08d1 <JSObject>
    1: decodeRLEChannel [000001AB9BEC0C81] [D:\work\2c-frontend\psd-parser\node_modules\psd\lib\psd\image_formats\rle.coffee:~28] [pc=00000078057459D3](this=0x009a26e375b9 <ChannelImage map = 000000907B832669>)
    2: parseChannelData [0000007D70B25A19] [D:\work\2c-frontend\psd-parser\node_modules\psd\lib\psd\image_formats\layer_rle.coffee:13] [bytecode=00...

FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
 1: 00007FF71EFA180F napi_wrap+119407
 2: 00007FF71EF487E6 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NextTableOffset+38102
 3: 00007FF71EF495E6 node::OnFatalError+438
 4: 00007FF71F785A6E v8::Isolate::ReportExternalAllocationLimitReached+94
 5: 00007FF71F76DC21 v8::SharedArrayBuffer::Externalize+833
 6: 00007FF71F61F3FC v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1436
 7: 00007FF71F63C41B v8::internal::Factory::NewFixedArrayWithFiller+59
 8: 00007FF71F63C3D1 v8::internal::Factory::NewFixedArray+65
 9: 00007FF71F518E6F v8::debug::Script::GetIsolate+8527
10: 00007FF71F3C6EDA v8::internal::interpreter::JumpTableTargetOffsets::iterator::operator=+162938
11: 00007FF71FBDABBD v8::internal::SetupIsolateDelegate::SetupHeap+546925
12: 00000078057459D3

my device is windows10, 16G ram.
and node version is 12.20.0
psd version is 3.2.0

Good day.

Hi @xty1992a,
It looks like you may be using Node.js. Have you tried increasing the max memory usage of your node process with --max-old-space-size=<memory in MB>?

Hi @xty1992a, It looks like you may be using Node.js. Have you tried increasing the max memory usage of your node process with --max-old-space-size=<memory in MB>?

Yes but still.

I google this that say this flag is useless now

Versions of Node that are >= 12 should not need to use the --optimize_for_size and --max_old_space_size flags because JavaScript heap limit will be based on available memory.

And I had print the process. memoryUsage() before toPng and after.

when I export some image that smaller then the collapse one, It use about 100-200MB memory.

I`ll post the detail later : )

Ahh interesting, in that case the process should use as much available memory as possible. Could either be that there's a leak somewhere in the code or that the file is just that dang large. Either way unfortunately don't have an easy solution to this. I'll take a look at the details if you post them.

sorry for waiting...

test code below

PSD.open(root("data/psd/1/地产20.psd"))
  .then(async (psd) => {
    const tree = psd.tree();
    const children = tree.children();
    const big = children.find((it) => it.name === "131369335"); // some image 3543 * 2657
    // const big = children.find((it) => it.name === "313682976"); // some image 5406 * 6235
    console.log(big.layer.image);
    console.log("before", process.memoryUsage());
    const png = big.layer.image.toPng();
    console.log("after", process.memoryUsage());
    return png;
  })
  .then(() => {
    console.log("Finished!");
  })
  .catch((e) => {
    console.log("error", e.message);
  });

the print

before {
  rss: 121024512,
  heapTotal: 26951680,
  heapUsed: 11277496,
  external: 74811088,
  arrayBuffers: 73624113
}
after {
  rss: 1889210368,
  heapTotal: 1790042112,
  heapUsed: 1754777680,
  external: 112403396,
  arrayBuffers: 111216381
}

You can download this psd for test also

Interesting! Thanks for posting more information. I'm a bit locked up this week but I'll try and take a look at this case over the weekend.