ag-psd 15.1.0 → 15.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ import {
8
8
  SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment,
9
9
  CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel,
10
10
  PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem,
11
- BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline,
11
+ BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue,
12
12
  } from './psd';
13
13
  import {
14
14
  PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16,
@@ -26,7 +26,8 @@ import {
26
26
  unitsPercent, unitsValue, WarpDescriptor, warpStyle, writeVersionAndDescriptor,
27
27
  readVersionAndDescriptor, StrokeDescriptor, Ornt, horzVrtcToXY, LmfxDescriptor, Lfx2Descriptor,
28
28
  FrameListDescriptor, TimelineDescriptor, FrameDescriptor, xyToHorzVrtc, serializeEffects,
29
- parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList, serializeTrackList, FractionDescriptor,
29
+ parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList,
30
+ serializeTrackList, FractionDescriptor,
30
31
  } from './descriptor';
31
32
  import { serializeEngineData, parseEngineData } from './engineData';
32
33
  import { encodeEngineData, decodeEngineData } from './text';
@@ -110,15 +111,17 @@ addHandler(
110
111
  };
111
112
 
112
113
  if (text.EngineData) {
113
- const engineData = decodeEngineData(parseEngineData(text.EngineData));
114
+ const engineData = parseEngineData(text.EngineData);
115
+ const textData = decodeEngineData(engineData);
114
116
 
117
+ // require('fs').writeFileSync(`layer-${target.name}.txt`, require('util').inspect(engineData, false, 99, false), 'utf8');
115
118
  // const before = parseEngineData(text.EngineData);
116
119
  // const after = encodeEngineData(engineData);
117
120
  // require('fs').writeFileSync('before.txt', require('util').inspect(before, false, 99, false), 'utf8');
118
121
  // require('fs').writeFileSync('after.txt', require('util').inspect(after, false, 99, false), 'utf8');
119
122
 
120
123
  // console.log(require('util').inspect(parseEngineData(text.EngineData), false, 99, true));
121
- target.text = { ...target.text, ...engineData };
124
+ target.text = { ...target.text, ...textData };
122
125
  // console.log(require('util').inspect(target.text, false, 99, true));
123
126
  }
124
127
 
@@ -1149,6 +1152,256 @@ addHandler(
1149
1152
  },
1150
1153
  );
1151
1154
 
1155
+ interface HrznVrtcDescriptor {
1156
+ Hrzn: DescriptorUnitsValue;
1157
+ Vrtc: DescriptorUnitsValue;
1158
+ }
1159
+
1160
+ interface SoLdDescriptorFilter {
1161
+ enab: boolean,
1162
+ validAtPosition: boolean,
1163
+ filterMaskEnable: boolean,
1164
+ filterMaskLinked: boolean,
1165
+ filterMaskExtendWithWhite: boolean,
1166
+ filterFXList: {
1167
+ 'Nm ': string;
1168
+ blendOptions: {
1169
+ Opct: DescriptorUnitsValue;
1170
+ 'Md ': string; // blend mode
1171
+ };
1172
+ enab: boolean;
1173
+ hasoptions: boolean;
1174
+ FrgC: DescriptorColor;
1175
+ BckC: DescriptorColor;
1176
+ Fltr: {
1177
+ 'null': string[]; // [Ordn.Trgt]
1178
+ rigidType: boolean;
1179
+ puppetShapeList: {
1180
+ rigidType: boolean;
1181
+ VrsM: number;
1182
+ VrsN: number;
1183
+ originalVertexArray: Uint8Array;
1184
+ deformedVertexArray: Uint8Array;
1185
+ indexArray: Uint8Array;
1186
+ pinOffsets: number[];
1187
+ posFinalPins: number[];
1188
+ pinVertexIndices: number[];
1189
+ PinP: number[];
1190
+ PnRt: number[];
1191
+ PnOv: boolean[];
1192
+ PnDp: number[];
1193
+ meshQuality: number;
1194
+ meshExpansion: number;
1195
+ meshRigidity: number;
1196
+ imageResolution: number;
1197
+ meshBoundaryPath: {
1198
+ pathComponents: {
1199
+ shapeOperation: string; // shapeOperation.xor
1200
+ SbpL: {
1201
+ Clsp: boolean;
1202
+ 'Pts ': {
1203
+ Anch: HrznVrtcDescriptor;
1204
+ 'Fwd ': HrznVrtcDescriptor;
1205
+ 'Bwd ': HrznVrtcDescriptor;
1206
+ Smoo: boolean;
1207
+ }[];
1208
+ }[];
1209
+ }[];
1210
+ };
1211
+ selectedPin: number[];
1212
+ }[];
1213
+ PuX0: number;
1214
+ PuX1: number;
1215
+ PuX2: number;
1216
+ PuX3: number;
1217
+ PuY0: number;
1218
+ PuY1: number;
1219
+ PuY2: number;
1220
+ PuY3: number;
1221
+ };
1222
+ filterID: number;
1223
+ }[];
1224
+ }
1225
+
1226
+ function uint8ToFloat32(array: Uint8Array) {
1227
+ return new Float32Array(array.buffer.slice(array.byteOffset), 0, array.byteLength / 4);
1228
+ }
1229
+
1230
+ function uint8ToUint32(array: Uint8Array) {
1231
+ return new Uint32Array(array.buffer.slice(array.byteOffset), 0, array.byteLength / 4);
1232
+ }
1233
+
1234
+ function toUint8(array: Uint32Array | Float32Array) {
1235
+ return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
1236
+ }
1237
+
1238
+ function arrayToPoints(array: number[] | Uint32Array | Float32Array) {
1239
+ const points: { x: number; y: number }[] = [];
1240
+
1241
+ for (let i = 0; i < array.length; i += 2) {
1242
+ points.push({ x: array[i], y: array[i + 1] });
1243
+ }
1244
+
1245
+ return points;
1246
+ }
1247
+
1248
+ function pointsToArray(points: { x: number; y: number }[]) {
1249
+ const array: number[] = [];
1250
+ for (let i = 0; i < points.length; i++) {
1251
+ array.push(points[i].x, points[i].y);
1252
+ }
1253
+ return array;
1254
+ }
1255
+
1256
+ function uin8ToPoints(array: Uint8Array) {
1257
+ return arrayToPoints(uint8ToFloat32(array));
1258
+ }
1259
+
1260
+ function hrznVrtcToPoint(desc: HrznVrtcDescriptor) {
1261
+ return {
1262
+ x: parseUnits(desc.Hrzn),
1263
+ y: parseUnits(desc.Vrtc),
1264
+ };
1265
+ }
1266
+
1267
+ function pointToHrznVrtc(point: { x: UnitsValue; y: UnitsValue; }): HrznVrtcDescriptor {
1268
+ return {
1269
+ Hrzn: unitsValue(point.x, 'x'),
1270
+ Vrtc: unitsValue(point.y, 'y'),
1271
+ };
1272
+ }
1273
+
1274
+ function parseFilterFX(desc: SoLdDescriptorFilter): PlacedLayerFilter {
1275
+ return {
1276
+ enabled: desc.enab,
1277
+ validAtPosition: desc.validAtPosition,
1278
+ maskEnabled: desc.filterMaskEnable,
1279
+ maskLinked: desc.filterMaskLinked,
1280
+ maskExtendWithWhite: desc.filterMaskExtendWithWhite,
1281
+ list: desc.filterFXList.map(f => ({
1282
+ id: f.filterID,
1283
+ name: f['Nm '],
1284
+ opacity: parsePercent(f.blendOptions.Opct),
1285
+ blendMode: BlnM.decode(f.blendOptions['Md ']),
1286
+ enabled: f.enab,
1287
+ hasOptions: f.hasoptions,
1288
+ foregroundColor: parseColor(f.FrgC),
1289
+ backgroundColor: parseColor(f.BckC),
1290
+ filter: {
1291
+ rigidType: f.Fltr.rigidType,
1292
+ bounds: [
1293
+ { x: f.Fltr.PuX0, y: f.Fltr.PuY0, },
1294
+ { x: f.Fltr.PuX1, y: f.Fltr.PuY1, },
1295
+ { x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
1296
+ { x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
1297
+ ],
1298
+ puppetShapeList: f.Fltr.puppetShapeList.map(p => ({
1299
+ rigidType: p.rigidType,
1300
+ // TODO: VrsM
1301
+ // TODO: VrsN
1302
+ originalVertexArray: uin8ToPoints(p.originalVertexArray),
1303
+ deformedVertexArray: uin8ToPoints(p.deformedVertexArray),
1304
+ indexArray: Array.from(uint8ToUint32(p.indexArray)),
1305
+ pinOffsets: arrayToPoints(p.pinOffsets),
1306
+ posFinalPins: arrayToPoints(p.posFinalPins),
1307
+ pinVertexIndices: p.pinVertexIndices,
1308
+ selectedPin: p.selectedPin,
1309
+ pinPosition: arrayToPoints(p.PinP),
1310
+ pinRotation: p.PnRt,
1311
+ pinOverlay: p.PnOv,
1312
+ pinDepth: p.PnDp,
1313
+ meshQuality: p.meshQuality,
1314
+ meshExpansion: p.meshExpansion,
1315
+ meshRigidity: p.meshRigidity,
1316
+ imageResolution: p.imageResolution,
1317
+ meshBoundaryPath: {
1318
+ pathComponents: p.meshBoundaryPath.pathComponents.map(c => ({
1319
+ shapeOperation: c.shapeOperation.split('.')[1],
1320
+ paths: c.SbpL.map(t => ({
1321
+ closed: t.Clsp,
1322
+ points: t['Pts '].map(pt => ({
1323
+ anchor: hrznVrtcToPoint(pt.Anch),
1324
+ forward: hrznVrtcToPoint(pt['Fwd ']),
1325
+ backward: hrznVrtcToPoint(pt['Bwd ']),
1326
+ smooth: pt.Smoo,
1327
+ })),
1328
+ })),
1329
+ })),
1330
+ },
1331
+ })),
1332
+ },
1333
+ })),
1334
+ };
1335
+ }
1336
+
1337
+ function serializeFilterFX(filter: PlacedLayerFilter): SoLdDescriptorFilter {
1338
+ return {
1339
+ enab: filter.enabled,
1340
+ validAtPosition: filter.validAtPosition,
1341
+ filterMaskEnable: filter.maskEnabled,
1342
+ filterMaskLinked: filter.maskLinked,
1343
+ filterMaskExtendWithWhite: filter.maskExtendWithWhite,
1344
+ filterFXList: filter.list.map(f => ({
1345
+ 'Nm ': f.name,
1346
+ blendOptions: {
1347
+ Opct: unitsPercent(f.opacity),
1348
+ 'Md ': BlnM.encode(f.blendMode),
1349
+ },
1350
+ enab: f.enabled,
1351
+ hasoptions: f.hasOptions,
1352
+ FrgC: serializeColor(f.foregroundColor),
1353
+ BckC: serializeColor(f.backgroundColor),
1354
+ Fltr: {
1355
+ 'null': ['Ordn.Trgt'], // ???
1356
+ rigidType: f.filter.rigidType,
1357
+ puppetShapeList: f.filter.puppetShapeList.map(p => ({
1358
+ rigidType: p.rigidType,
1359
+ VrsM: 1, // TODO: ...
1360
+ VrsN: 0, // TODO: ...
1361
+ originalVertexArray: toUint8(new Float32Array(pointsToArray(p.originalVertexArray))),
1362
+ deformedVertexArray: toUint8(new Float32Array(pointsToArray(p.deformedVertexArray))),
1363
+ indexArray: toUint8(new Uint32Array(p.indexArray)),
1364
+ pinOffsets: pointsToArray(p.pinOffsets),
1365
+ posFinalPins: pointsToArray(p.posFinalPins),
1366
+ selectedPin: p.selectedPin,
1367
+ pinVertexIndices: p.pinVertexIndices,
1368
+ PinP: pointsToArray(p.pinPosition),
1369
+ PnRt: p.pinRotation,
1370
+ PnOv: p.pinOverlay,
1371
+ PnDp: p.pinDepth,
1372
+ meshQuality: p.meshQuality,
1373
+ meshExpansion: p.meshExpansion,
1374
+ meshRigidity: p.meshRigidity,
1375
+ imageResolution: p.imageResolution,
1376
+ meshBoundaryPath: {
1377
+ pathComponents: p.meshBoundaryPath.pathComponents.map(c => ({
1378
+ shapeOperation: `shapeOperation.${c.shapeOperation}`,
1379
+ SbpL: c.paths.map(path => ({
1380
+ Clsp: path.closed,
1381
+ 'Pts ': path.points.map(pt => ({
1382
+ Anch: pointToHrznVrtc(pt.anchor),
1383
+ 'Fwd ': pointToHrznVrtc(pt.forward),
1384
+ 'Bwd ': pointToHrznVrtc(pt.backward),
1385
+ Smoo: pt.smooth,
1386
+ })),
1387
+ })),
1388
+ })),
1389
+ },
1390
+ })),
1391
+ PuX0: f.filter.bounds[0].x,
1392
+ PuX1: f.filter.bounds[1].x,
1393
+ PuX2: f.filter.bounds[2].x,
1394
+ PuX3: f.filter.bounds[3].x,
1395
+ PuY0: f.filter.bounds[0].y,
1396
+ PuY1: f.filter.bounds[1].y,
1397
+ PuY2: f.filter.bounds[2].y,
1398
+ PuY3: f.filter.bounds[3].y,
1399
+ },
1400
+ filterID: f.id,
1401
+ })),
1402
+ };
1403
+ }
1404
+
1152
1405
  interface SoLdDescriptor {
1153
1406
  Idnt: string;
1154
1407
  placed: string;
@@ -1166,8 +1419,10 @@ interface SoLdDescriptor {
1166
1419
  warp: WarpDescriptor;
1167
1420
  'Sz ': { Wdth: number; Hght: number; };
1168
1421
  Rslt: DescriptorUnitsValue;
1422
+ filterFX?: SoLdDescriptorFilter;
1169
1423
  comp?: number;
1170
1424
  compInfo?: { compID: number; originalCompID: number; };
1425
+ Impr?: {}; // ???
1171
1426
  }
1172
1427
 
1173
1428
  addHandler(
@@ -1181,6 +1436,8 @@ addHandler(
1181
1436
  // console.log('SoLd', require('util').inspect(desc, false, 99, true));
1182
1437
  // console.log('SoLd.warp', require('util').inspect(desc.warp, false, 99, true));
1183
1438
  // console.log('SoLd.quiltWarp', require('util').inspect(desc.quiltWarp, false, 99, true));
1439
+ // desc.filterFX!.filterFXList[0].Fltr.puppetShapeList[0].meshBoundaryPath.pathComponents[0].SbpL[0]['Pts '] = [];
1440
+ // console.log('filterFX', require('util').inspect(desc.filterFX, false, 99, true));
1184
1441
 
1185
1442
  target.placedLayer = {
1186
1443
  id: desc.Idnt,
@@ -1205,6 +1462,7 @@ addHandler(
1205
1462
  if (desc.Crop) target.placedLayer.crop = desc.Crop;
1206
1463
  if (desc.comp) target.placedLayer.comp = desc.comp;
1207
1464
  if (desc.compInfo) target.placedLayer.compInfo = desc.compInfo;
1465
+ if (desc.filterFX) target.placedLayer.filter = parseFilterFX(desc.filterFX);
1208
1466
 
1209
1467
  skipBytes(reader, left()); // HACK
1210
1468
  },
@@ -1235,6 +1493,8 @@ addHandler(
1235
1493
  Rslt: placed.resolution ? unitsValue(placed.resolution, 'resolution') : { units: 'Density', value: 72 },
1236
1494
  };
1237
1495
 
1496
+ if (placed.filter) desc.filterFX = serializeFilterFX(placed.filter);
1497
+
1238
1498
  if (placed.warp && isQuiltWarp(placed.warp)) {
1239
1499
  const quiltWarp = encodeWarp(placed.warp) as QuiltWarpDescriptor;
1240
1500
  desc.quiltWarp = quiltWarp;
@@ -2675,3 +2935,85 @@ addHandler(
2675
2935
  writeZeros(writer, 3);
2676
2936
  },
2677
2937
  );
2938
+
2939
+ /*addHandler(
2940
+ 'FEid',
2941
+ hasKey('filterEffects'),
2942
+ (reader, _target) => {
2943
+ const version = readInt32(reader);
2944
+ if (version < 1 || version > 3) throw new Error(`Invalid filterEffects version ${version}`);
2945
+
2946
+ if (readUint32(reader)) throw new Error('filterEffects: 64 bit length is not supported');
2947
+ const length = readUint32(reader);
2948
+ const end = reader.offset + length;
2949
+
2950
+ while (reader.offset < end) {
2951
+ console.log('bytes to go', end - reader.offset, 'at', reader.offset.toString(16));
2952
+ //
2953
+ const id = readPascalString(reader, 1);
2954
+ const effectVersion = readInt32(reader);
2955
+ if (effectVersion !== 1) throw new Error(`Invalid filterEffect version ${effectVersion}`);
2956
+ if (readUint32(reader)) throw new Error('filterEffect: 64 bit length is not supported');
2957
+ const effectLength = readUint32(reader);
2958
+ const endOfEffect = reader.offset + effectLength;
2959
+ const top = readInt32(reader);
2960
+ const left = readInt32(reader);
2961
+ const bottom = readInt32(reader);
2962
+ const right = readInt32(reader);
2963
+ const depth = readInt32(reader);
2964
+ const maxChannels = readInt32(reader);
2965
+ const channels: any[] = [];
2966
+
2967
+ for (let i = 0; i < (maxChannels + 2); i++) {
2968
+ const exists = readInt32(reader);
2969
+ if (exists) {
2970
+ if (readUint32(reader)) throw new Error('filterEffect: 64 bit length is not supported');
2971
+ const channelLength = readUint32(reader);
2972
+ const compressionMode = readUint16(reader);
2973
+ const data = readBytes(reader, channelLength - 2);
2974
+ channels.push({ channelLength, compressionMode, data: data?.length + ' bytes' });
2975
+ // if (c < 3 || c == 25) e_ = _F.Cn(!0, rL, m, b.rect.F, b.rect.V, X, rp);
2976
+ // if (c == 0) _c.S = e_;
2977
+ // if (c == 1) _c.v = e_;
2978
+ // if (c == 2) _c.e = e_;
2979
+ // if (c == 25) _c.w = e_;
2980
+ } else {
2981
+ channels.push(undefined);
2982
+ }
2983
+ }
2984
+
2985
+ console.log('left at the end', endOfEffect - reader.offset);
2986
+ if (endOfEffect > reader.offset) {
2987
+ if (readUint8(reader)) {
2988
+ const compressionMode = readUint16(reader);
2989
+ const data = endOfEffect > reader.offset ? readBytes(reader, endOfEffect - reader.offset) : undefined;
2990
+ console.log('extra data', { compressionMode, data: data?.length + ' bytes' });
2991
+ } else {
2992
+ console.log('no extra');
2993
+ }
2994
+ }
2995
+
2996
+ console.log('effect', {
2997
+ id,
2998
+ effectVersion,
2999
+ effectLength,
3000
+ top,
3001
+ left,
3002
+ bottom,
3003
+ right,
3004
+ depth,
3005
+ maxChannels,
3006
+ channels,
3007
+ });
3008
+
3009
+ console.log('bytes left after effect', endOfEffect - reader.offset);
3010
+ // if (length % 4) skipBytes(reader, 4 - length % 4);
3011
+ }
3012
+
3013
+ console.log({ version, length });
3014
+ },
3015
+ (_writer, _target) => {
3016
+ },
3017
+ );
3018
+
3019
+ addHandlerAlias('FXid', 'FEid');*/
package/src/descriptor.ts CHANGED
@@ -121,6 +121,15 @@ const fieldToExtType: ExtTypeDict = {
121
121
  'Lnk ': makeType('', 'ExternalFileLink'),
122
122
  frameReader: makeType('', 'FrameReader'),
123
123
  effectParams: makeType('', 'motionTrackEffectParams'),
124
+ Impr: makeType('None', 'none'),
125
+ Anch: makeType('', 'Pnt '),
126
+ 'Fwd ': makeType('', 'Pnt '),
127
+ 'Bwd ': makeType('', 'Pnt '),
128
+ meshBoundaryPath: makeType('', 'pathClass'),
129
+ filterFX: makeType('', 'filterFXStyle'),
130
+ Fltr: makeType('', 'rigidTransform'),
131
+ FrgC: makeType('', 'RGBC'),
132
+ BckC: makeType('', 'RGBC'),
124
133
  };
125
134
 
126
135
  const fieldToArrayExtType: ExtTypeDict = {
@@ -145,6 +154,11 @@ const fieldToArrayExtType: ExtTypeDict = {
145
154
  countObjectList: makeType('', 'countObject'),
146
155
  countGroupList: makeType('', 'countGroup'),
147
156
  slices: makeType('', 'slice'),
157
+ 'Pts ': makeType('', 'Pthp'),
158
+ SbpL: makeType('', 'SbpL'),
159
+ pathComponents: makeType('', 'PaCm'),
160
+ filterFXList: makeType('', 'filterFX'),
161
+ puppetShapeList: makeType('', 'puppetShape'),
148
162
  };
149
163
 
150
164
  const typeToField: { [key: string]: string[]; } = {
@@ -154,7 +168,7 @@ const typeToField: { [key: string]: string[]; } = {
154
168
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
155
169
  'altTag', 'url', 'cellText',
156
170
  ],
157
- 'tdta': ['EngineData', 'LUT3DFileData'],
171
+ 'tdta': ['EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray'],
158
172
  'long': [
159
173
  'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
160
174
  'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'presetKind', 'comp', 'compID', 'originalCompID',
@@ -164,7 +178,8 @@ const typeToField: { [key: string]: string[]; } = {
164
178
  'numModifyingFX', 'deformNumRows', 'deformNumCols', 'FrID', 'FrDl', 'FsID', 'LCnt', 'AFrm', 'AFSt',
165
179
  'numBefore', 'numAfter', 'Spcn', 'minOpacity', 'maxOpacity', 'BlnM', 'sheetID', 'gblA', 'globalAltitude',
166
180
  'descVersion', 'frameReaderType', 'LyrI', 'zoomOrigin', 'fontSize', 'Rds ', 'sliceID',
167
- 'topOutset', 'leftOutset', 'bottomOutset', 'rightOutset',
181
+ 'topOutset', 'leftOutset', 'bottomOutset', 'rightOutset', 'filterID', 'meshQuality',
182
+ 'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN',
168
183
  ],
169
184
  'enum': [
170
185
  'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS',
@@ -173,7 +188,7 @@ const typeToField: { [key: string]: string[]; } = {
173
188
  'strokeStyleBlendMode', 'PntT', 'Styl', 'lookupType', 'LUTFormat', 'dataOrder',
174
189
  'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
175
190
  'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
176
- 'vertAlign', 'bgColorType',
191
+ 'vertAlign', 'bgColorType', 'shapeOperation',
177
192
  ],
178
193
  'bool': [
179
194
  'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
@@ -184,13 +199,15 @@ const typeToField: { [key: string]: string[]; } = {
184
199
  'autoExpandEnabled', 'autoNestEnabled', 'autoPositionEnabled', 'shrinkwrapOnSaveEnabled',
185
200
  'present', 'showInDialog', 'overprint', 'sheetDisclosed', 'lightsDisclosed', 'meshesDisclosed',
186
201
  'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
187
- 'cellTextIsHTML',
202
+ 'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
203
+ 'filterMaskLinked', 'filterMaskExtendWithWhite',
188
204
  ],
189
205
  'doub': [
190
206
  'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
191
207
  'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
192
208
  'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
193
- 'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat',
209
+ 'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
210
+ 'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3'
194
211
  ],
195
212
  'UntF': [
196
213
  'Scl ', 'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
@@ -203,7 +220,8 @@ const typeToField: { [key: string]: string[]; } = {
203
220
  'LaSt', 'Trnf', 'nonAffineTransform', 'keyDescriptorList', 'guideIndeces', 'gradientFillMulti',
204
221
  'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
205
222
  'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
206
- 'warpValues',
223
+ 'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
224
+ 'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList',
207
225
  ],
208
226
  'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
209
227
  'obj ': ['null'],
@@ -216,24 +234,37 @@ const channels = [
216
234
  const fieldToArrayType: Dict = {
217
235
  'Mnm ': 'long',
218
236
  'Mxm ': 'long',
219
- 'FrLs': 'long',
220
- 'strokeStyleLineDashSet': 'UntF',
221
- 'Trnf': 'doub',
222
- 'nonAffineTransform': 'doub',
223
- 'keyDescriptorList': 'Objc',
224
- 'gradientFillMulti': 'Objc',
225
- 'solidFillMulti': 'Objc',
226
- 'frameFXMulti': 'Objc',
227
- 'innerShadowMulti': 'Objc',
228
- 'dropShadowMulti': 'Objc',
229
- 'LaSt': 'Objc',
230
- 'FrIn': 'Objc',
231
- 'FSts': 'Objc',
232
- 'FsFr': 'long',
233
- 'blendOptions': 'Objc',
234
- 'sheetTimelineOptions': 'Objc',
235
- 'keyList': 'Objc',
236
- 'warpValues': 'doub',
237
+ FrLs: 'long',
238
+ strokeStyleLineDashSet: 'UntF',
239
+ Trnf: 'doub',
240
+ nonAffineTransform: 'doub',
241
+ keyDescriptorList: 'Objc',
242
+ gradientFillMulti: 'Objc',
243
+ solidFillMulti: 'Objc',
244
+ frameFXMulti: 'Objc',
245
+ innerShadowMulti: 'Objc',
246
+ dropShadowMulti: 'Objc',
247
+ LaSt: 'Objc',
248
+ FrIn: 'Objc',
249
+ FSts: 'Objc',
250
+ FsFr: 'long',
251
+ blendOptions: 'Objc',
252
+ sheetTimelineOptions: 'Objc',
253
+ keyList: 'Objc',
254
+ warpValues: 'doub',
255
+ selectedPin: 'long',
256
+ 'Pts ': 'Objc',
257
+ SbpL: 'Objc',
258
+ pathComponents: 'Objc',
259
+ pinOffsets: 'doub',
260
+ posFinalPins: 'doub',
261
+ pinVertexIndices: 'long',
262
+ PinP: 'doub',
263
+ PnRt: 'long',
264
+ PnOv: 'bool',
265
+ PnDp: 'doub',
266
+ filterFXList: 'Objc',
267
+ puppetShapeList: 'Objc',
237
268
  };
238
269
 
239
270
  const fieldToType: Dict = {};
@@ -494,7 +525,7 @@ function writeOSType(writer: PsdWriter, type: string, value: any, key: string, e
494
525
  for (let i = 0; i < value.length; i++) {
495
526
  const type = fieldToArrayType[key];
496
527
  writeSignature(writer, type || 'long');
497
- writeOSType(writer, type || 'long', value[i], '', fieldToArrayExtType[key], root);
528
+ writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
498
529
  if (logErrors && !type) console.log(`Missing descriptor array type for: '${key}' in`, value);
499
530
  }
500
531
  break;
package/src/psd.ts CHANGED
@@ -674,6 +674,62 @@ export interface LinkedFile {
674
674
  assetLockedState?: number;
675
675
  }
676
676
 
677
+ export interface PlacedLayerFilter {
678
+ enabled: boolean;
679
+ validAtPosition: boolean;
680
+ maskEnabled: boolean;
681
+ maskLinked: boolean;
682
+ maskExtendWithWhite: boolean;
683
+ list: {
684
+ id: number;
685
+ name: string;
686
+ opacity: number;
687
+ blendMode: BlendMode;
688
+ enabled: boolean;
689
+ hasOptions: boolean;
690
+ foregroundColor: Color;
691
+ backgroundColor: Color;
692
+ filter: {
693
+ rigidType: boolean;
694
+ bounds: { x: number; y: number; }[];
695
+ puppetShapeList: {
696
+ rigidType: boolean;
697
+ // VrsM: number;
698
+ // VrsN: number;
699
+ originalVertexArray: { x: number; y: number; }[];
700
+ deformedVertexArray: { x: number; y: number; }[];
701
+ indexArray: number[];
702
+ pinOffsets: { x: number; y: number; }[];
703
+ posFinalPins: { x: number; y: number; }[];
704
+ pinVertexIndices: number[];
705
+ selectedPin: number[];
706
+ pinPosition: { x: number; y: number; }[];
707
+ pinRotation: number[]; // in degrees
708
+ pinOverlay: boolean[];
709
+ pinDepth: number[];
710
+ meshQuality: number;
711
+ meshExpansion: number;
712
+ meshRigidity: number;
713
+ imageResolution: number;
714
+ meshBoundaryPath: {
715
+ pathComponents: {
716
+ shapeOperation: string;
717
+ paths: {
718
+ closed: boolean;
719
+ points: {
720
+ anchor: { x: UnitsValue; y: UnitsValue; };
721
+ forward: { x: UnitsValue; y: UnitsValue; };
722
+ backward: { x: UnitsValue; y: UnitsValue; };
723
+ smooth: boolean;
724
+ }[];
725
+ }[];
726
+ }[];
727
+ };
728
+ }[];
729
+ };
730
+ }[];
731
+ }
732
+
677
733
  export type PlacedLayerType = 'unknown' | 'vector' | 'raster' | 'image stack';
678
734
 
679
735
  export interface PlacedLayer {
@@ -695,6 +751,7 @@ export interface PlacedLayer {
695
751
  crop?: number;
696
752
  comp?: number;
697
753
  compInfo?: { compID: number; originalCompID: number; };
754
+ filter?: PlacedLayerFilter;
698
755
  }
699
756
 
700
757
  export type AdjustmentLayer = BrightnessAdjustment | LevelsAdjustment | CurvesAdjustment |
@@ -894,6 +951,7 @@ export interface LayerAdditionalInfo {
894
951
  unifyLayerVisibility?: boolean;
895
952
  };
896
953
  timeline?: Timeline;
954
+ filterEffects?: any;
897
955
 
898
956
  // Base64 encoded raw EngineData, currently just kept in original state to support
899
957
  // loading and modifying PSD file without breaking text layers.
package/src/text.ts CHANGED
@@ -498,6 +498,7 @@ export function decodeEngineData(engineData: EngineData) {
498
498
  for (let i = 0; i < styleRun.RunArray.length; i++) {
499
499
  const length = styleRun.RunLengthArray[i];
500
500
  const style = decodeStyle(styleRun.RunArray[i].StyleSheet.StyleSheetData, fonts);
501
+ if (!style.font) style.font = fonts[0];
501
502
  result.styleRuns.push({ length, style });
502
503
  }
503
504