Agamnentzar / ag-psd

Javascript library for reading and writing PSD files
Other
489 stars 66 forks source link

save psd error #143

Closed winderzhang closed 4 months ago

winderzhang commented 1 year ago

const fs = require('fs');
require('ag-psd/initialize-canvas');
const { readPsd, writePsdBuffer } = require('ag-psd');

const travelLayer = (layer) => {
  if (layer.canvas) {
    layer.canvas = null
  }
  if (layer.text) {
    console.log(layer.text.text);
    // layer.text.text = 'New Text';
    // layer.canvas = canvas;
    console.log(layer.text.text, layer.canvas);
    // parent.children.splice(index, 1)
  }
  if (layer.children) {
    layer.children.forEach((l, idx) => travelLayer(l, layer, idx))
  }
}

const main = async () => {
  // 读取 PSD 文件
  const buffer = await fs.readFileSync('./static/psd/test.psd');
  const psd = readPsd(buffer, {
    skipLayerImageData: true,
    skipCompositeImageData: true,
    skipThumbnail: true,
    skipLinkedFilesData: true,
    throwForMissingFeatures: true,
    logMissingFeatures: true,
    useImageData: true,
    useRawThumbnail: true,
    logDevFeatures: true
  });
  const outputBuffer = writePsdBuffer(psd, {
    invalidateTextLayers: true
  });
  fs.writeFileSync('./output/test.psd', outputBuffer);
}
main();`

TypeError: Cannot read properties of undefined (reading 'map')
    at D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:990:59
    at Array.map (<anonymous>)
    at serializeFilterFX (D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:977:35)
    at Object.write (D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:1086:25)
    at D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:407:25
    at writeSection (D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:151:5)
    at _loop_4 (D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:406:13)
    at writeAdditionalLayerInfo (D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:413:9)
    at D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:300:17
    at writeSection (D:\01-project\image-translate\node_modules\ag-psd\dist\psdWriter.js:151:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Agamnentzar commented 1 year ago

@winderzhang is it possible for you to send the PSD file that causes the issue? I can fix it without but it would be better to know why this is happening.

Agamnentzar commented 1 year ago

I release version 15.3.1 that should handle missing arrays correctly

winderzhang commented 1 year ago

@winderzhang is it possible for you to send the PSD file that causes the issue? I can fix it without but it would be better to know why this is happening.

thank you for your reply,I'm very sorry that I can't give the original PSD, it's a confidential project。

if i use throwForMissingFeatures = true, the error happend, const psd = readPsd(buffer, { logMissingFeatures: true, throwForMissingFeatures: true });

so, i add console in the complied code ,here list: desc.filterFXList.map(function (f) { console.log(f.Fltr) return ({ id: f.filterID, name: f['Nm '], opacity: (0, descriptor_1.parsePercent)(f.blendOptions.Opct), blendMode: descriptor_1.BlnM.decode(f.blendOptions['Md ']), enabled: f.enab, hasOptions: f.hasoptions, foregroundColor: (0, descriptor_1.parseColor)(f.FrgC), backgroundColor: (0, descriptor_1.parseColor)(f.BckC), filter: { rigidType: f.Fltr.rigidType, bounds: [ { x: f.Fltr.PuX0, y: f.Fltr.PuY0, }, { x: f.Fltr.PuX1, y: f.Fltr.PuY1, }, { x: f.Fltr.PuX2, y: f.Fltr.PuY2, }, { x: f.Fltr.PuX3, y: f.Fltr.PuY3, }, ], puppetShapeList: f.Fltr.puppetShapeList.map(function (p) { return ({ rigidType: p.rigidType, // TODO: VrsM // TODO: VrsN originalVertexArray: uin8ToPoints(p.originalVertexArray), deformedVertexArray: uin8ToPoints(p.deformedVertexArray), indexArray: Array.from(uint8ToUint32(p.indexArray)), pinOffsets: arrayToPoints(p.pinOffsets), posFinalPins: arrayToPoints(p.posFinalPins), pinVertexIndices: p.pinVertexIndices, selectedPin: p.selectedPin, pinPosition: arrayToPoints(p.PinP), pinRotation: p.PnRt, pinOverlay: p.PnOv, pinDepth: p.PnDp, meshQuality: p.meshQuality, meshExpansion: p.meshExpansion, meshRigidity: p.meshRigidity, imageResolution: p.imageResolution, meshBoundaryPath: { pathComponents: p.meshBoundaryPath.pathComponents.map(function (c) { return ({ shapeOperation: c.shapeOperation.split('.')[1], paths: c.SbpL.map(function (t) { return ({ closed: t.Clsp, points: t['Pts '].map(function (pt) { return ({ anchor: hrznVrtcToPoint(pt.Anch), forward: hrznVrtcToPoint(pt['Fwd ']), backward: hrznVrtcToPoint(pt['Bwd ']), smooth: pt.Smoo, }); }), }); }), }); }), }, }); }), }, }); }),, this is the console ` { LqMe: Uint8Array(382092) [ 0, 0, 0, 4, 121, 102, 113, 76, 104, 115, 101, 77, 2, 0, 0, 0, 1, 4, 0, 0, 71, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 94, 5, 0, 0, 149, 10, 0, 0, 29, 9, 0, 0, 6, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 9, 0, 0, 6, 16, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, 1, 4, 0, 0, ... 381992 more items ] } D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:931 puppetShapeList: f.Fltr.puppetShapeList.map(function (p) { return ({ ^

TypeError: Cannot read properties of undefined (reading 'map') at D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:931:57 at Array.map () at parseFilterFX (D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:912:33) at Object.read (D:\01-project\image-translate\node_modules\ag-psd\dist\additionalInfo.js:1073:37) at D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:577:25 at readSection (D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:819:18) at readAdditionalLayerInfo (D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:573:5) at D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:381:13 at readSection (D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:819:18) at readLayerRecord (D:\01-project\image-translate\node_modules\ag-psd\dist\psdReader.js:374:5) error Command failed with exit code 1. `

Agamnentzar commented 1 year ago

could you add console.log(desc) somewhere there and send me what it prints, I can add workaround for this error but it will not save or read the file correctly anymore because the library is not handling correctly the filter you have on your smart layer.

winderzhang commented 1 year ago

desc.filterFXList.map

i add console.log(desc) here

function parseFilterFX(desc) {
    return {
        enabled: desc.enab,
        validAtPosition: desc.validAtPosition,
        maskEnabled: desc.filterMaskEnable,
        maskLinked: desc.filterMaskLinked,
        maskExtendWithWhite: desc.filterMaskExtendWithWhite,
        list: desc.filterFXList.map(function (f) { 
            console.log('the desc is: ', desc)
            return ({
            id: f.filterID,
            name: f['Nm  '],
            opacity: (0, descriptor_1.parsePercent)(f.blendOptions.Opct),
            blendMode: descriptor_1.BlnM.decode(f.blendOptions['Md  ']),
            enabled: f.enab,
            hasOptions: f.hasoptions,
            foregroundColor: (0, descriptor_1.parseColor)(f.FrgC),
            backgroundColor: (0, descriptor_1.parseColor)(f.BckC),
            filter: {
                rigidType: f.Fltr.rigidType,
                bounds: [
                    { x: f.Fltr.PuX0, y: f.Fltr.PuY0, },
                    { x: f.Fltr.PuX1, y: f.Fltr.PuY1, },
                    { x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
                    { x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
                ],
                puppetShapeList: f.Fltr.puppetShapeList.map(function (p) { return ({
                    rigidType: p.rigidType,
                    // TODO: VrsM
                    // TODO: VrsN
                    originalVertexArray: uin8ToPoints(p.originalVertexArray),
                    deformedVertexArray: uin8ToPoints(p.deformedVertexArray),
                    indexArray: Array.from(uint8ToUint32(p.indexArray)),
                    pinOffsets: arrayToPoints(p.pinOffsets),
                    posFinalPins: arrayToPoints(p.posFinalPins),
                    pinVertexIndices: p.pinVertexIndices,
                    selectedPin: p.selectedPin,
                    pinPosition: arrayToPoints(p.PinP),
                    pinRotation: p.PnRt,
                    pinOverlay: p.PnOv,
                    pinDepth: p.PnDp,
                    meshQuality: p.meshQuality,
                    meshExpansion: p.meshExpansion,
                    meshRigidity: p.meshRigidity,
                    imageResolution: p.imageResolution,
                    meshBoundaryPath: {
                        pathComponents: p.meshBoundaryPath.pathComponents.map(function (c) { return ({
                            shapeOperation: c.shapeOperation.split('.')[1],
                            paths: c.SbpL.map(function (t) { return ({
                                closed: t.Clsp,
                                points: t['Pts '].map(function (pt) { return ({
                                    anchor: hrznVrtcToPoint(pt.Anch),
                                    forward: hrznVrtcToPoint(pt['Fwd ']),
                                    backward: hrznVrtcToPoint(pt['Bwd ']),
                                    smooth: pt.Smoo,
                                }); }),
                            }); }),
                        }); }),
                    },
                }); }),
            },
        }); }),
    };
}

and the print is this

the desc is:  {
  enab: true,
  validAtPosition: true, 
  filterMaskEnable: true,
  filterMaskLinked: false,
  filterMaskExtendWithWhite: true,
  filterFXList: [
    {
      'Nm  ': '液化...',
      blendOptions: [Object],
      enab: true,
      hasoptions: true,
      FrgC: [Object],
      BckC: [Object],
      Fltr: [Object],
      filterID: 1282492025
    },
    {
      'Nm  ': '液化...',
      blendOptions: [Object],
      enab: true,
      hasoptions: true,
      FrgC: [Object],
      BckC: [Object],
      Fltr: [Object],
      filterID: 1282492025
    }
  ]
}
winderzhang commented 1 year ago

and i also print the desc.filterFXList array content, code like this

list: desc.filterFXList.map(function (f) { 
            console.log('the desc is: ', desc);
            console.log('the f is: ', f)
            return ({
            id: f.filterID,
            name: f['Nm  '],
            opacity: (0, descriptor_1.parsePercent)(f.blendOptions.Opct),
            blendMode: descriptor_1.BlnM.decode(f.blendOptions['Md  ']),
            enabled: f.enab,
            hasOptions: f.hasoptions,
            foregroundColor: (0, descriptor_1.parseColor)(f.FrgC),
            backgroundColor: (0, descriptor_1.parseColor)(f.BckC),
            filter: {
                rigidType: f.Fltr.rigidType,
                bounds: [
                    { x: f.Fltr.PuX0, y: f.Fltr.PuY0, },
                    { x: f.Fltr.PuX1, y: f.Fltr.PuY1, },
                    { x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
                    { x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
                ],
                puppetShapeList: f.Fltr.puppetShapeList.map(function (p) { return ({
                    rigidType: p.rigidType,
                    // TODO: VrsM
                    // TODO: VrsN
                    originalVertexArray: uin8ToPoints(p.originalVertexArray),
                    deformedVertexArray: uin8ToPoints(p.deformedVertexArray),
                    indexArray: Array.from(uint8ToUint32(p.indexArray)),
                    pinOffsets: arrayToPoints(p.pinOffsets),
                    posFinalPins: arrayToPoints(p.posFinalPins),
                    pinVertexIndices: p.pinVertexIndices,
                    selectedPin: p.selectedPin,
                    pinPosition: arrayToPoints(p.PinP),
                    pinRotation: p.PnRt,
                    pinOverlay: p.PnOv,
                    pinDepth: p.PnDp,
                    meshQuality: p.meshQuality,
                    meshExpansion: p.meshExpansion,
                    meshRigidity: p.meshRigidity,
                    imageResolution: p.imageResolution,
                    meshBoundaryPath: {
                        pathComponents: p.meshBoundaryPath.pathComponents.map(function (c) { return ({
                            shapeOperation: c.shapeOperation.split('.')[1],
                            paths: c.SbpL.map(function (t) { return ({
                                closed: t.Clsp,
                                points: t['Pts '].map(function (pt) { return ({
                                    anchor: hrznVrtcToPoint(pt.Anch),
                                    forward: hrznVrtcToPoint(pt['Fwd ']),
                                    backward: hrznVrtcToPoint(pt['Bwd ']),
                                    smooth: pt.Smoo,
                                }); }),
                            }); }),
                        }); }),
                    },
                }); }),
            },
        }); }),

the print content

the desc is:  {
  enab: true,
  validAtPosition: true,
  filterMaskEnable: true,
  filterMaskLinked: false,        
  filterMaskExtendWithWhite: true,
  filterFXList: [
    {
      'Nm  ': '液化...',
      blendOptions: [Object],     
      enab: true,
      hasoptions: true,
      FrgC: [Object],
      BckC: [Object],
      Fltr: [Object],
      filterID: 1282492025        
    },
    {
      'Nm  ': '液化...',
      blendOptions: [Object],     
      enab: true,
      hasoptions: true,
      FrgC: [Object],
      BckC: [Object],
      Fltr: [Object],
      filterID: 1282492025
    }
  ]
}
the f is:  {
  'Nm  ': '液化...',
  blendOptions: { Opct: { units: 'Percent', value: 100 }, 'Md  ': 'BlnM.Nrml' },
  enab: true,
  hasoptions: true,
  FrgC: {
    'Rd  ': 81.00389376282692,
    'Grn ': 30.00000011175871,
    'Bl  ': 22.000000588595867
  },
  BckC: {
    'H   ': { units: 'Angle', value: 308.5345458984375 },
    Strt: 0,
    Brgh: 100
  },
  Fltr: {
    LqMe: Uint8Array(382092) [
        0,  0, 0, 4, 121, 102, 113, 76, 104, 115, 101, 77,
        2,  0, 0, 0,   1,   4,   0,  0,  71,   2,   0,  0,
        0,  0, 0, 0,   1,   0,   0,  0,  94,   5,   0,  0,
      149, 10, 0, 0,  29,   9,   0,  0,   6,  16,   0,  0,
        0,  0, 0, 0,   0,   0,   0,  0,  29,   9,   0,  0,
        6, 16, 0, 0,   1,   4,   0,  0,   1,   4,   0,  0,
        1,  4, 0, 0,   1,   4,   0,  0,   1,   4,   0,  0,
        1,  4, 0, 0,   1,   4,   0,  0,   1,   4,   0,  0,
        1,  4, 0, 0,
      ... 381992 more items
    ]
  },
  filterID: 1282492025
}

thanks

Agamnentzar commented 1 year ago

What kind of filter is applied to the smart layer? I'm trying to figure out what LqMe field is supposed to be. Maybe you can provide a screenshot of the layer panel in photoshop.

winderzhang commented 1 year ago

image

winderzhang commented 1 year ago

image

Agamnentzar commented 1 year ago

Added support for the filter in version 17.0.0 Had to rework how smart layer filters work.