ag-psd 33.0.0 → 34.0.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.
Files changed (86) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/d13d7610 +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  18. package/CHANGELOG.md +22 -0
  19. package/README.md +1 -1
  20. package/README_PSD.md +25 -9
  21. package/TODO.md +13 -84
  22. package/dist/abr.js +12 -7
  23. package/dist/abr.js.map +1 -1
  24. package/dist/additionalInfo.d.ts +2 -0
  25. package/dist/additionalInfo.js +361 -75
  26. package/dist/additionalInfo.js.map +1 -1
  27. package/dist/bundle.js +1524 -389
  28. package/dist/descriptor.d.ts +14 -5
  29. package/dist/descriptor.js +102 -64
  30. package/dist/descriptor.js.map +1 -1
  31. package/dist/helpers.d.ts +6 -0
  32. package/dist/helpers.js +242 -2
  33. package/dist/helpers.js.map +1 -1
  34. package/dist/imageResources.js +84 -3
  35. package/dist/imageResources.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/psd.d.ts +144 -2
  40. package/dist/psd.js.map +1 -1
  41. package/dist/psdReader.js +206 -110
  42. package/dist/psdReader.js.map +1 -1
  43. package/dist/psdWriter.d.ts +1 -0
  44. package/dist/psdWriter.js +336 -91
  45. package/dist/psdWriter.js.map +1 -1
  46. package/dist/text.d.ts +32 -1
  47. package/dist/text.js +58 -0
  48. package/dist/text.js.map +1 -1
  49. package/dist-es/abr.js +12 -7
  50. package/dist-es/abr.js.map +1 -1
  51. package/dist-es/additionalInfo.d.ts +2 -0
  52. package/dist-es/additionalInfo.js +361 -75
  53. package/dist-es/additionalInfo.js.map +1 -1
  54. package/dist-es/descriptor.d.ts +14 -5
  55. package/dist-es/descriptor.js +102 -64
  56. package/dist-es/descriptor.js.map +1 -1
  57. package/dist-es/helpers.d.ts +6 -0
  58. package/dist-es/helpers.js +242 -2
  59. package/dist-es/helpers.js.map +1 -1
  60. package/dist-es/imageResources.js +84 -3
  61. package/dist-es/imageResources.js.map +1 -1
  62. package/dist-es/index.d.ts +1 -0
  63. package/dist-es/index.js +1 -0
  64. package/dist-es/index.js.map +1 -1
  65. package/dist-es/psd.d.ts +144 -2
  66. package/dist-es/psd.js.map +1 -1
  67. package/dist-es/psdReader.js +206 -110
  68. package/dist-es/psdReader.js.map +1 -1
  69. package/dist-es/psdWriter.d.ts +1 -0
  70. package/dist-es/psdWriter.js +336 -91
  71. package/dist-es/psdWriter.js.map +1 -1
  72. package/dist-es/text.d.ts +32 -1
  73. package/dist-es/text.js +58 -0
  74. package/dist-es/text.js.map +1 -1
  75. package/package.json +1 -1
  76. package/perf.js +312 -9
  77. package/src/abr.ts +14 -7
  78. package/src/additionalInfo.ts +433 -87
  79. package/src/descriptor.ts +103 -58
  80. package/src/helpers.ts +262 -2
  81. package/src/imageResources.ts +107 -4
  82. package/src/index.ts +1 -0
  83. package/src/psd.ts +115 -2
  84. package/src/psdReader.ts +226 -108
  85. package/src/psdWriter.ts +345 -90
  86. package/src/text.ts +76 -1
@@ -108,11 +108,77 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
108
108
  (0, psdWriter_1.writeFloat32)(writer, (_d = text.bottom) !== null && _d !== void 0 ? _d : 0);
109
109
  // writeZeros(writer, 2);
110
110
  });
111
+ // type tool info from Photoshop 5.0 and 5.5, converted to regular text data (written as 'TySh')
112
+ addHandler('tySh', () => false, (reader, target, left) => {
113
+ if ((0, psdReader_1.readInt16)(reader) !== 1)
114
+ throw new Error(`Invalid tySh version`);
115
+ const transform = [];
116
+ for (let i = 0; i < 6; i++)
117
+ transform.push((0, psdReader_1.readFloat64)(reader));
118
+ if ((0, psdReader_1.readInt16)(reader) !== 6)
119
+ throw new Error(`Invalid tySh font version`);
120
+ const data = { transform, faces: [], styles: [], lines: [], color: { r: 0, g: 0, b: 0 }, antiAlias: false };
121
+ const facesCount = (0, psdReader_1.readInt16)(reader);
122
+ for (let i = 0; i < facesCount; i++) {
123
+ const mark = (0, psdReader_1.readInt16)(reader);
124
+ (0, psdReader_1.readInt32)(reader); // font type
125
+ const name = (0, psdReader_1.readPascalString)(reader, 1);
126
+ const familyName = (0, psdReader_1.readPascalString)(reader, 1);
127
+ const styleName = (0, psdReader_1.readPascalString)(reader, 1);
128
+ const script = (0, psdReader_1.readInt16)(reader);
129
+ const axesCount = (0, psdReader_1.readInt32)(reader);
130
+ if (axesCount < 0 || axesCount * 4 > left())
131
+ throw new Error(`Invalid tySh design axes count`);
132
+ (0, psdReader_1.skipBytes)(reader, axesCount * 4);
133
+ data.faces.push({ mark, name, familyName, styleName, script });
134
+ }
135
+ const stylesCount = (0, psdReader_1.readInt16)(reader);
136
+ for (let i = 0; i < stylesCount; i++) {
137
+ const mark = (0, psdReader_1.readInt16)(reader);
138
+ const faceMark = (0, psdReader_1.readInt16)(reader);
139
+ const size = (0, psdReader_1.readInt32)(reader);
140
+ const tracking = (0, psdReader_1.readInt32)(reader);
141
+ const kerning = (0, psdReader_1.readInt32)(reader);
142
+ const leading = (0, psdReader_1.readInt32)(reader);
143
+ const baselineShift = (0, psdReader_1.readInt32)(reader);
144
+ const autoKerning = !!(0, psdReader_1.readUint8)(reader);
145
+ (0, psdReader_1.readUint8)(reader); // rotate
146
+ data.styles.push({ mark, faceMark, size, tracking, kerning, leading, baselineShift, autoKerning });
147
+ }
148
+ (0, psdReader_1.readInt16)(reader); // type (0 = point, 1 = paragraph)
149
+ (0, psdReader_1.readInt32)(reader); // scaling factor
150
+ (0, psdReader_1.readInt32)(reader); // character count
151
+ (0, psdReader_1.readInt32)(reader); // horizontal placement
152
+ (0, psdReader_1.readInt32)(reader); // vertical placement
153
+ (0, psdReader_1.readInt32)(reader); // select start
154
+ (0, psdReader_1.readInt32)(reader); // select end
155
+ const linesCount = (0, psdReader_1.readInt16)(reader);
156
+ for (let i = 0; i < linesCount; i++) {
157
+ const charCount = (0, psdReader_1.readInt32)(reader);
158
+ const orientation = (0, psdReader_1.readInt16)(reader);
159
+ const alignment = (0, psdReader_1.readInt16)(reader);
160
+ if (charCount < 0 || charCount * 4 > left())
161
+ throw new Error(`Invalid tySh character count`);
162
+ const chars = [];
163
+ for (let j = 0; j < charCount; j++) {
164
+ const code = (0, psdReader_1.readUint16)(reader);
165
+ const style = (0, psdReader_1.readInt16)(reader);
166
+ chars.push({ code, style });
167
+ }
168
+ data.lines.push({ orientation, alignment, chars });
169
+ }
170
+ data.color = (0, psdReader_1.readColor)(reader);
171
+ data.antiAlias = !!(0, psdReader_1.readUint8)(reader);
172
+ if (!target.text)
173
+ target.text = (0, text_1.decodeLegacyTextData)(data);
174
+ (0, psdReader_1.skipBytes)(reader, left());
175
+ }, () => { });
111
176
  // vector fills
112
177
  addHandler('SoCo', target => target.vectorFill !== undefined && target.vectorStroke === undefined &&
113
- target.vectorFill.type === 'color', (reader, target) => {
178
+ target.vectorFill.type === 'color', (reader, target, left) => {
114
179
  const descriptor = (0, descriptor_1.readVersionAndDescriptor)(reader);
115
180
  target.vectorFill = (0, descriptor_1.parseVectorContent)(descriptor);
181
+ (0, psdReader_1.skipBytes)(reader, left());
116
182
  }, (writer, target) => {
117
183
  const { descriptor } = (0, descriptor_1.serializeVectorContent)(target.vectorFill);
118
184
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
@@ -401,10 +467,10 @@ addHandler('lmfx', target => target.effects !== undefined && !isGroupLayer(targe
401
467
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
402
468
  // console.log('READ', require('util').inspect(desc, false, 99, true));
403
469
  // discard if read in 'lrFX' or 'lfx2' section
404
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
470
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
405
471
  (0, psdReader_1.skipBytes)(reader, left());
406
- }, (writer, target, _, options) => {
407
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
472
+ }, (writer, target) => {
473
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
408
474
  // console.log('WRITE', require('util').inspect(desc, false, 99, true));
409
475
  (0, psdWriter_1.writeUint32)(writer, 0); // version
410
476
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
@@ -539,6 +605,58 @@ addHandler('lmgm', hasKey('layerMaskAsGlobalMask'), (reader, target) => {
539
605
  (0, psdWriter_1.writeUint8)(writer, target.layerMaskAsGlobalMask ? 1 : 0);
540
606
  (0, psdWriter_1.writeZeros)(writer, 3);
541
607
  });
608
+ addHandler('vmgm', hasKey('vectorMaskAsGlobalMask'), (reader, target) => {
609
+ target.vectorMaskAsGlobalMask = !!(0, psdReader_1.readUint8)(reader);
610
+ (0, psdReader_1.skipBytes)(reader, 3);
611
+ }, (writer, target) => {
612
+ (0, psdWriter_1.writeUint8)(writer, target.vectorMaskAsGlobalMask ? 1 : 0);
613
+ (0, psdWriter_1.writeZeros)(writer, 3);
614
+ });
615
+ addHandler('ffxi', hasKey('foreignEffectId'), (reader, target) => {
616
+ target.foreignEffectId = (0, psdReader_1.readInt32)(reader);
617
+ }, (writer, target) => {
618
+ (0, psdWriter_1.writeInt32)(writer, target.foreignEffectId);
619
+ });
620
+ addHandler('shpa', hasKey('patternData'), (reader, target, left) => {
621
+ if ((0, psdReader_1.readInt32)(reader) !== 0)
622
+ throw new Error(`Invalid shpa version`);
623
+ const count = (0, psdReader_1.readInt32)(reader);
624
+ target.patternData = [];
625
+ for (let i = 0; i < count && left() > 0; i++) {
626
+ const signature = (0, psdReader_1.readSignature)(reader);
627
+ const key = (0, psdReader_1.readSignature)(reader);
628
+ const patternsCount = (0, psdReader_1.readInt32)(reader);
629
+ const copyOnSheetDuplication = !!(0, psdReader_1.readUint8)(reader);
630
+ (0, psdReader_1.skipBytes)(reader, 3);
631
+ const patterns = [];
632
+ for (let j = 0; j < patternsCount && left() > 0; j++) {
633
+ const colorHandling = descriptor_1.patternColorHandling.decode('.' + (0, psdReader_1.readSignature)(reader));
634
+ (0, psdReader_1.readPascalString)(reader, 1); // name
635
+ const name = (0, psdReader_1.readUnicodeString)(reader);
636
+ const id = (0, psdReader_1.readPascalString)(reader, 1);
637
+ patterns.push({ colorHandling, name, id });
638
+ }
639
+ target.patternData.push({ signature, key, copyOnSheetDuplication, patterns });
640
+ }
641
+ (0, psdReader_1.skipBytes)(reader, left());
642
+ }, (writer, target) => {
643
+ const sets = target.patternData;
644
+ (0, psdWriter_1.writeInt32)(writer, 0); // version
645
+ (0, psdWriter_1.writeInt32)(writer, sets.length);
646
+ for (const set of sets) {
647
+ (0, psdWriter_1.writeSignature)(writer, set.signature);
648
+ (0, psdWriter_1.writeSignature)(writer, set.key);
649
+ (0, psdWriter_1.writeInt32)(writer, set.patterns.length);
650
+ (0, psdWriter_1.writeUint8)(writer, set.copyOnSheetDuplication ? 1 : 0);
651
+ (0, psdWriter_1.writeZeros)(writer, 3);
652
+ for (const pattern of set.patterns) {
653
+ (0, psdWriter_1.writeSignature)(writer, descriptor_1.patternColorHandling.encode(pattern.colorHandling).split('.')[1]);
654
+ (0, psdWriter_1.writePascalString)(writer, pattern.name.replace(/[^\x20-\x7e]/g, '?'), 1);
655
+ (0, psdWriter_1.writeUnicodeString)(writer, pattern.name);
656
+ (0, psdWriter_1.writePascalString)(writer, pattern.id, 1);
657
+ }
658
+ }
659
+ });
542
660
  addHandler('lspf', hasKey('protected'), (reader, target) => {
543
661
  const flags = (0, psdReader_1.readUint32)(reader);
544
662
  target.protected = {
@@ -643,7 +761,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
643
761
  if (f.FXRf)
644
762
  frame.referencePoint = (0, descriptor_1.horzVrtcToXY)(f.FXRf);
645
763
  if (f.Lefx)
646
- frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, !!reader.logMissingFeatures);
764
+ frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, reader);
647
765
  if (f.blendOptions && f.blendOptions.Opct)
648
766
  frame.opacity = (0, descriptor_1.parsePercent)(f.blendOptions.Opct);
649
767
  target.animationFrames.push(frame);
@@ -674,7 +792,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
674
792
  audioLevel: desc.audioLevel,
675
793
  };
676
794
  if (desc.trackList) {
677
- timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, !!reader.logMissingFeatures);
795
+ timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, reader);
678
796
  }
679
797
  target.timeline = timeline;
680
798
  // console.log('tmln:result', target.name, target.id, require('util').inspect(timeline, false, 99, true));
@@ -756,7 +874,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
756
874
  if (f.referencePoint)
757
875
  frame.FXRf = (0, descriptor_1.xyToHorzVrtc)(f.referencePoint);
758
876
  if (f.effects)
759
- frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, false, hasMultiEffects(f.effects));
877
+ frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, writer, hasMultiEffects(f.effects));
760
878
  if (f.opacity !== undefined)
761
879
  frame.blendOptions = { Opct: (0, descriptor_1.unitsPercentF)(f.opacity) };
762
880
  desc.LaSt.push(frame);
@@ -796,7 +914,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
796
914
  audioLevel: timeline.audioLevel,
797
915
  };
798
916
  if (timeline.tracks) {
799
- desc.trackList = (0, descriptor_1.serializeTrackList)(timeline.tracks);
917
+ desc.trackList = (0, descriptor_1.serializeTrackList)(timeline.tracks, writer);
800
918
  }
801
919
  desc.LyrI = getLayerId(target, options);
802
920
  // console.log('WRITE:tmln', target.name, target.id, require('util').inspect(desc, false, 99, true));
@@ -1175,6 +1293,86 @@ function pointToHrznVrtc(point) {
1175
1293
  Vrtc: (0, descriptor_1.unitsValue)(point.y, 'y'),
1176
1294
  };
1177
1295
  }
1296
+ // Camera Raw Filter setting paths (in CameraRawFilterSettings) and their descriptor keys
1297
+ const cameraRawColorKeys = [
1298
+ ['red', 'R'], ['orange', 'O'], ['yellow', 'Y'], ['green', 'G'], ['aqua', 'A'], ['blue', 'B'], ['purple', 'P'], ['magenta', 'M'],
1299
+ ];
1300
+ const cameraRawSettings = [
1301
+ ['version', 'CrVe'], ['processVersion', 'PrVN'], ['processVersionCode', 'PrVe'], ['whiteBalance', 'WBal'],
1302
+ ['temperature', 'Temp'], ['tint', 'Tint'], ['exposure', 'Ex12'], ['contrast', 'Cr12'], ['highlights', 'Hi12'],
1303
+ ['shadows', 'Sh12'], ['whites', 'Wh12'], ['blacks', 'Bk12'], ['texture', 'CrTx'], ['clarity', 'Cl12'],
1304
+ ['dehaze', 'Dhze'], ['vibrance', 'Vibr'], ['saturation', 'Strt'],
1305
+ ['parametricCurve.shadows', 'PC_S'], ['parametricCurve.darks', 'PC_D'], ['parametricCurve.lights', 'PC_L'],
1306
+ ['parametricCurve.highlights', 'PC_H'], ['parametricCurve.shadowSplit', 'PC_1'], ['parametricCurve.midtoneSplit', 'PC_2'],
1307
+ ['parametricCurve.highlightSplit', 'PC_3'],
1308
+ ['pointCurve.composite', 'Crv '], ['pointCurve.red', 'CrvR'], ['pointCurve.green', 'CrvG'], ['pointCurve.blue', 'CrvB'],
1309
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.hue.${name}`, `HA_${key}`]),
1310
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.saturation.${name}`, `SA_${key}`]),
1311
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.luminance.${name}`, `LA_${key}`]),
1312
+ ['colorGrading.shadows.hue', 'STSH'], ['colorGrading.shadows.saturation', 'STSS'], ['colorGrading.shadows.luminance', 'CgSL'],
1313
+ ['colorGrading.midtones.hue', 'CgMH'], ['colorGrading.midtones.saturation', 'CgMS'], ['colorGrading.midtones.luminance', 'CgML'],
1314
+ ['colorGrading.highlights.hue', 'STHH'], ['colorGrading.highlights.saturation', 'STHS'], ['colorGrading.highlights.luminance', 'CgHL'],
1315
+ ['colorGrading.global.hue', 'CgGH'], ['colorGrading.global.saturation', 'CgGS'], ['colorGrading.global.luminance', 'CgGL'],
1316
+ ['colorGrading.blending', 'CgBl'], ['colorGrading.balance', 'STB '],
1317
+ ['sharpening.amount', 'Shrp'], ['sharpening.radius', 'ShpR'], ['sharpening.detail', 'ShpD'], ['sharpening.masking', 'ShpM'],
1318
+ ['noiseReduction.luminance', 'LNR '], ['noiseReduction.luminanceDetail', 'LNRD'], ['noiseReduction.luminanceContrast', 'LNRC'],
1319
+ ['noiseReduction.color', 'CNR '], ['noiseReduction.colorDetail', 'CNRD'], ['noiseReduction.colorSmoothness', 'CNRS'],
1320
+ ['grain.amount', 'GRNA'], ['grain.size', 'GRNS'], ['grain.roughness', 'GRNF'],
1321
+ ['postCropVignette.amount', 'PCVA'], ['postCropVignette.midpoint', 'PCVM'], ['postCropVignette.feather', 'PCVF'],
1322
+ ['postCropVignette.roundness', 'PCVR'],
1323
+ ];
1324
+ const cameraRawCurveKeys = ['Crv ', 'CrvR', 'CrvG', 'CrvB'];
1325
+ const cameraRawFilterID = 2783;
1326
+ function parseCameraRawSettings(desc, reader) {
1327
+ var _a;
1328
+ const settings = {};
1329
+ for (const [path, key] of cameraRawSettings) {
1330
+ let value = desc[key];
1331
+ if (value === undefined)
1332
+ continue;
1333
+ if (key === 'WBal') {
1334
+ value = value.split('.')[1];
1335
+ }
1336
+ else if (cameraRawCurveKeys.includes(key)) {
1337
+ const values = value;
1338
+ value = [];
1339
+ for (let i = 0; i + 1 < values.length; i += 2)
1340
+ value.push({ input: values[i], output: values[i + 1] });
1341
+ }
1342
+ const parts = path.split('.');
1343
+ let target = settings;
1344
+ for (let i = 0; i < parts.length - 1; i++)
1345
+ target = target[parts[i]] = (_a = target[parts[i]]) !== null && _a !== void 0 ? _a : {};
1346
+ target[parts[parts.length - 1]] = value;
1347
+ }
1348
+ for (const key of Object.keys(desc)) {
1349
+ if (key !== '_name' && key !== '_classID' && !cameraRawSettings.some(s => s[1] === key)) {
1350
+ reader.logMissingFeatures && reader.log(`Unhandled Camera Raw Filter setting: ${key}`);
1351
+ }
1352
+ }
1353
+ return settings;
1354
+ }
1355
+ function serializeCameraRawSettings(settings) {
1356
+ const desc = { _name: '', _classID: descriptor_1.cameraRawFilterClassID };
1357
+ for (const [path, key] of cameraRawSettings) {
1358
+ let value = settings;
1359
+ for (const part of path.split('.'))
1360
+ value = value === null || value === void 0 ? void 0 : value[part];
1361
+ if (value === undefined)
1362
+ continue;
1363
+ if (key === 'WBal') {
1364
+ value = `WBal.${value}`;
1365
+ }
1366
+ else if (cameraRawCurveKeys.includes(key)) {
1367
+ value = value.flatMap(p => [Math.round(p.input), Math.round(p.output)]);
1368
+ }
1369
+ else if (typeof value === 'number' && key !== 'Ex12' && key !== 'ShpR') {
1370
+ value = Math.round(value);
1371
+ }
1372
+ desc[key] = value;
1373
+ }
1374
+ return desc;
1375
+ }
1178
1376
  function parseFilterFXItem(f, reader) {
1179
1377
  const base = {
1180
1378
  name: f['Nm '],
@@ -1185,6 +1383,9 @@ function parseFilterFXItem(f, reader) {
1185
1383
  foregroundColor: (0, descriptor_1.parseColor)(f.FrgC),
1186
1384
  backgroundColor: (0, descriptor_1.parseColor)(f.BckC),
1187
1385
  };
1386
+ if ('Fltr' in f && f.Fltr._classID === descriptor_1.cameraRawFilterClassID) {
1387
+ return Object.assign(Object.assign({}, base), { type: 'camera raw', filter: parseCameraRawSettings(f.Fltr, reader) });
1388
+ }
1188
1389
  if ('Fltr' in f) {
1189
1390
  switch (f.Fltr._classID) {
1190
1391
  case 'boxblur': return Object.assign(Object.assign({}, base), { type: 'box blur', filter: {
@@ -2083,6 +2284,7 @@ function serializeFilterFXItem(f) {
2083
2284
  return adjustment;
2084
2285
  }),
2085
2286
  } : {})), filterID: 1282829427 });
2287
+ case 'camera raw': return Object.assign(Object.assign({}, base), { Fltr: serializeCameraRawSettings(f.filter), filterID: cameraRawFilterID });
2086
2288
  case 'brightness/contrast': return Object.assign(Object.assign({}, base), { Fltr: {
2087
2289
  _name: 'Brightness/Contrast',
2088
2290
  _classID: 'BrgC',
@@ -2308,31 +2510,23 @@ addHandler('LMsk', hasKey('userMask'), (reader, target) => {
2308
2510
  (0, psdWriter_1.writeUint8)(writer, 128);
2309
2511
  (0, psdWriter_1.writeZeros)(writer, 1);
2310
2512
  });
2311
- if (helpers_1.MOCK_HANDLERS) {
2312
- addHandler('Patt', target => target._Patt !== undefined, (reader, target, left) => {
2313
- // console.log('additional info: Patt');
2314
- target._Patt = (0, psdReader_1.readBytes)(reader, left());
2315
- }, (writer, target) => false && (0, psdWriter_1.writeBytes)(writer, target._Patt));
2316
- }
2317
- else {
2318
- addHandler('Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2319
- // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2320
- target => !!(target.patterns && target.patterns.length > 0), (reader, target, left) => {
2321
- while (left() > 0) {
2322
- const pattern = (0, psdReader_1.readPatternSafe)(reader);
2323
- if (!pattern)
2324
- continue;
2325
- if (target.patterns === undefined)
2326
- target.patterns = [];
2327
- target.patterns.push(pattern);
2328
- }
2329
- }, (writer, target, _, _options) => {
2330
- const patterns = target.patterns || [];
2331
- for (const pattern of patterns) {
2332
- (0, psdWriter_1.writePattern)(writer, pattern);
2333
- }
2334
- });
2335
- }
2513
+ addHandler('Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2514
+ // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2515
+ target => !!(target.patterns && target.patterns.length > 0), (reader, target, left) => {
2516
+ while (left() > 0) {
2517
+ const pattern = (0, psdReader_1.readPatternSafe)(reader);
2518
+ if (!pattern)
2519
+ continue;
2520
+ if (target.patterns === undefined)
2521
+ target.patterns = [];
2522
+ target.patterns.push(pattern);
2523
+ }
2524
+ }, (writer, target, _, _options) => {
2525
+ const patterns = target.patterns || [];
2526
+ for (const pattern of patterns) {
2527
+ (0, psdWriter_1.writePattern)(writer, pattern);
2528
+ }
2529
+ });
2336
2530
  addHandlerAlias('Pat2', 'Patt');
2337
2531
  addHandlerAlias('Pat3', 'Patt');
2338
2532
  /*
@@ -2724,10 +2918,10 @@ target => target.effects !== undefined && isGroupLayer(target), (reader, target,
2724
2918
  if (version !== 0)
2725
2919
  throw new Error(`Invalid lfxs version`);
2726
2920
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
2727
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
2921
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
2728
2922
  (0, psdReader_1.skipBytes)(reader, left());
2729
- }, (writer, target, _, options) => {
2730
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
2923
+ }, (writer, target) => {
2924
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
2731
2925
  (0, psdWriter_1.writeUint32)(writer, 0); // version
2732
2926
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
2733
2927
  });
@@ -2782,11 +2976,19 @@ addHandler('levl', adjustmentType('levels'), (reader, target, left) => {
2782
2976
  channels.push(readLevelsChannel(reader));
2783
2977
  }
2784
2978
  if (left() >= 8) {
2785
- if ((0, psdReader_1.readSignature)(reader) !== 'Lvls')
2786
- throw new Error(`Invalid levl signature`);
2787
- if ((0, psdReader_1.readUint16)(reader) !== 3)
2788
- throw new Error(`Invalid levl version`);
2789
- const totalChannelRecords = (0, psdReader_1.readUint16)(reader);
2979
+ const signature = (0, psdReader_1.readSignature)(reader);
2980
+ let totalChannelRecords;
2981
+ if (signature === 'ls\x00\x03') {
2982
+ // Clip Studio Paint writes 'ls' instead of 'Lvls' signature (version is part of the read signature)
2983
+ totalChannelRecords = (0, psdReader_1.readUint16)(reader);
2984
+ }
2985
+ else {
2986
+ if (signature !== 'Lvls')
2987
+ throw new Error(`Invalid levl signature`);
2988
+ if ((0, psdReader_1.readUint16)(reader) !== 3)
2989
+ throw new Error(`Invalid levl version`);
2990
+ totalChannelRecords = (0, psdReader_1.readUint16)(reader);
2991
+ }
2790
2992
  while (channels.length < totalChannelRecords && left() >= 10) {
2791
2993
  channels.push(readLevelsChannel(reader));
2792
2994
  }
@@ -2827,58 +3029,78 @@ function writeCurveChannel(writer, channel) {
2827
3029
  }
2828
3030
  }
2829
3031
  addHandler('curv', adjustmentType('curves'), (reader, target, left) => {
2830
- (0, psdReader_1.readUint8)(reader);
2831
- if ((0, psdReader_1.readUint16)(reader) !== 1)
3032
+ const isMap = !!(0, psdReader_1.readUint8)(reader); // curves drawn with pencil tool (lookup tables instead of points)
3033
+ const version = (0, psdReader_1.readUint16)(reader);
3034
+ if (version !== 1 && version !== 4)
2832
3035
  throw new Error('Invalid curv version');
2833
- (0, psdReader_1.readUint16)(reader);
2834
- const channelsMask = (0, psdReader_1.readUint16)(reader);
3036
+ const countOrMask = (0, psdReader_1.readUint32)(reader);
2835
3037
  const channels = [];
2836
- for (let i = 0; i < 16; i++) {
2837
- if (channelsMask & (1 << i)) {
2838
- while (channels.length < i)
3038
+ const readChannel = () => isMap ? Array.from((0, psdReader_1.readBytes)(reader, 256)) : readCurveChannel(reader);
3039
+ if (version === 1) {
3040
+ for (let i = 0; i < 32; i++) {
3041
+ if (countOrMask & (1 << i)) {
3042
+ while (channels.length < i)
3043
+ channels.push([]);
3044
+ channels.push(readChannel());
3045
+ }
3046
+ }
3047
+ }
3048
+ else {
3049
+ if (countOrMask > 64)
3050
+ throw new Error('Invalid curv channel count');
3051
+ for (let i = 0; i < countOrMask; i++)
3052
+ channels.push(readChannel());
3053
+ }
3054
+ // extra section stores curves for all channels (including ones that don't fit in the mask)
3055
+ if (version === 1 && left() >= 10 && (0, psdReader_1.readSignature)(reader) === 'Crv ') {
3056
+ (0, psdReader_1.readUint16)(reader); // version
3057
+ const count = (0, psdReader_1.readUint32)(reader);
3058
+ for (let i = 0; i < count && left() >= 2; i++) {
3059
+ const index = (0, psdReader_1.readUint16)(reader);
3060
+ const channel = readChannel();
3061
+ while (channels.length < index)
2839
3062
  channels.push([]);
2840
- channels.push(readCurveChannel(reader));
3063
+ channels[index] = channel;
2841
3064
  }
2842
3065
  }
2843
- target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'curves', channels });
2844
- // ignoring, duplicate information
2845
- // checkSignature(reader, 'Crv ');
2846
- // const cVersion = readUint16(reader);
2847
- // readUint16(reader);
2848
- // const channelCount = readUint16(reader);
2849
- // for (let i = 0; i < channelCount; i++) {
2850
- // const index = readUint16(reader);
2851
- // const nodes = readUint16(reader);
2852
- // for (let j = 0; j < nodes; j++) {
2853
- // const output = readInt16(reader);
2854
- // const input = readInt16(reader);
2855
- // }
2856
- // }
3066
+ target.adjustment = Object.assign(Object.assign(Object.assign({}, target.adjustment), { type: 'curves' }), (isMap ? { values: channels } : { channels: channels }));
2857
3067
  (0, psdReader_1.skipBytes)(reader, left());
2858
3068
  }, (writer, target) => {
2859
3069
  var _a;
2860
- const channels = (target.adjustment.channels || []).slice(0, 16);
3070
+ const adjustment = target.adjustment;
3071
+ const isMap = !!adjustment.values;
3072
+ const channels = (isMap ? adjustment.values : adjustment.channels) || [];
2861
3073
  const used = [];
2862
3074
  let channelsMask = 0;
2863
3075
  for (let i = 0; i < channels.length; i++) {
2864
3076
  if ((_a = channels[i]) === null || _a === void 0 ? void 0 : _a.length) {
2865
- channelsMask |= 1 << i;
3077
+ if (i < 32)
3078
+ channelsMask |= 1 << i;
2866
3079
  used.push(i);
2867
3080
  }
2868
3081
  }
2869
- (0, psdWriter_1.writeUint8)(writer, 0);
3082
+ const writeChannel = (channel) => {
3083
+ var _a;
3084
+ if (isMap) {
3085
+ for (let i = 0; i < 256; i++)
3086
+ (0, psdWriter_1.writeUint8)(writer, (0, helpers_1.clamp)(Math.round((_a = channel[i]) !== null && _a !== void 0 ? _a : i), 0, 255));
3087
+ }
3088
+ else {
3089
+ writeCurveChannel(writer, channel);
3090
+ }
3091
+ };
3092
+ (0, psdWriter_1.writeUint8)(writer, isMap ? 1 : 0);
2870
3093
  (0, psdWriter_1.writeUint16)(writer, 1); // version
2871
- (0, psdWriter_1.writeUint16)(writer, 0);
2872
- (0, psdWriter_1.writeUint16)(writer, channelsMask);
3094
+ (0, psdWriter_1.writeUint32)(writer, channelsMask >>> 0);
2873
3095
  for (const i of used)
2874
- writeCurveChannel(writer, channels[i]);
3096
+ if (i < 32)
3097
+ writeChannel(channels[i]);
2875
3098
  (0, psdWriter_1.writeSignature)(writer, 'Crv ');
2876
3099
  (0, psdWriter_1.writeUint16)(writer, 4); // version
2877
- (0, psdWriter_1.writeUint16)(writer, 0);
2878
- (0, psdWriter_1.writeUint16)(writer, used.length);
3100
+ (0, psdWriter_1.writeUint32)(writer, used.length);
2879
3101
  for (const i of used) {
2880
3102
  (0, psdWriter_1.writeUint16)(writer, i);
2881
- writeCurveChannel(writer, channels[i]);
3103
+ writeChannel(channels[i]);
2882
3104
  }
2883
3105
  });
2884
3106
  addHandler('expA', adjustmentType('exposure'), (reader, target, left) => {
@@ -3590,6 +3812,10 @@ addHandler('FEid', hasKey('filterEffectsMasks'), (reader, target, leftBytes) =>
3590
3812
  }
3591
3813
  });
3592
3814
  addHandlerAlias('FXid', 'FEid');
3815
+ addHandlerAlias('FELS', 'FEid'); // filter effects 3
3816
+ addHandlerAlias('hue ', 'hue2'); // old hue/saturation (Photoshop 4.0), same structure as 'hue2'
3817
+ addHandlerAlias('plLd', 'PlLd'); // old placed layer key
3818
+ addHandlerAlias('abdd', 'artb'); // artboard data 3
3593
3819
  addHandler('FMsk', hasKey('filterMask'), (reader, target) => {
3594
3820
  target.filterMask = {
3595
3821
  colorSpace: (0, psdReader_1.readColor)(reader),
@@ -3650,10 +3876,10 @@ addHandler('lfx2', target => target.effects !== undefined && !isGroupLayer(targe
3650
3876
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
3651
3877
  // console.log('READ', require('util').inspect(desc, false, 99, true));
3652
3878
  // discard if read in 'lrFX' section ('lmfx' and 'lfx2' are never stored together)
3653
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
3879
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
3654
3880
  (0, psdReader_1.skipBytes)(reader, left());
3655
- }, (writer, target, _, options) => {
3656
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
3881
+ }, (writer, target) => {
3882
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
3657
3883
  // console.log('WRITE', require('util').inspect(desc, false, 99, true));
3658
3884
  (0, psdWriter_1.writeUint32)(writer, 0); // version
3659
3885
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
@@ -3715,6 +3941,66 @@ addHandler('extn', target => target.generatorSettings !== undefined && isDocumen
3715
3941
  }, (writer, target) => {
3716
3942
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', serializeGeneratorSettings(target.generatorSettings));
3717
3943
  });
3944
+ // generator settings stored by older versions of Photoshop (written back in 'shmd' or 'extn' section)
3945
+ addHandler('extd', () => false, (reader, target, left) => {
3946
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
3947
+ if (desc.generatorSettings && target.generatorSettings === undefined) {
3948
+ target.generatorSettings = parseGeneratorSettings(desc.generatorSettings);
3949
+ }
3950
+ (0, psdReader_1.skipBytes)(reader, left());
3951
+ }, () => { });
3952
+ addHandler('frgb', // frame tool group
3953
+ hasKey('framedGroup'), (reader, target, left) => {
3954
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
3955
+ const rect = desc.framedGroupRect;
3956
+ target.framedGroup = {
3957
+ rect: { top: rect['Top '], left: rect.Left, bottom: rect.Btom, right: rect.Rght },
3958
+ type: desc.framedGroupType,
3959
+ };
3960
+ if (desc.LockPPI !== undefined)
3961
+ target.framedGroup.lockPPI = desc.LockPPI;
3962
+ if (desc.PreferredResolution !== undefined)
3963
+ target.framedGroup.preferredResolution = desc.PreferredResolution;
3964
+ if (desc.SavedIteratedName !== undefined)
3965
+ target.framedGroup.savedIteratedName = desc.SavedIteratedName;
3966
+ (0, psdReader_1.skipBytes)(reader, left());
3967
+ }, (writer, target) => {
3968
+ const group = target.framedGroup;
3969
+ const rect = group.rect;
3970
+ const desc = {
3971
+ framedGroupRect: { _name: '', _classID: 'classFloatRect', 'Top ': rect.top, Left: rect.left, Btom: rect.bottom, Rght: rect.right },
3972
+ framedGroupType: group.type,
3973
+ };
3974
+ if (group.lockPPI !== undefined)
3975
+ desc.LockPPI = group.lockPPI;
3976
+ if (group.preferredResolution !== undefined)
3977
+ desc.PreferredResolution = group.preferredResolution;
3978
+ if (group.savedIteratedName !== undefined)
3979
+ desc.SavedIteratedName = group.savedIteratedName;
3980
+ (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'framedGroup', desc);
3981
+ });
3982
+ addHandler('anFX', hasKey('animationEffects'), (reader, target, left) => {
3983
+ target.animationEffects = (0, psdReader_1.readBytes)(reader, left());
3984
+ }, (writer, target) => {
3985
+ (0, psdWriter_1.writeBytes)(writer, target.animationEffects);
3986
+ });
3987
+ addHandler('PxSD', // pixel source data 2 (video layer frames)
3988
+ hasKey('pixelSourceData'), (reader, target, left) => {
3989
+ target.pixelSourceData = [];
3990
+ while (left() >= 8) {
3991
+ const length = readLength64(reader);
3992
+ if (length > left())
3993
+ throw new Error('Invalid PxSD data length');
3994
+ target.pixelSourceData.push((0, psdReader_1.readBytes)(reader, length));
3995
+ }
3996
+ (0, psdReader_1.skipBytes)(reader, left());
3997
+ }, (writer, target) => {
3998
+ for (const data of target.pixelSourceData) {
3999
+ (0, psdWriter_1.writeUint32)(writer, 0);
4000
+ (0, psdWriter_1.writeUint32)(writer, data.byteLength);
4001
+ (0, psdWriter_1.writeBytes)(writer, data);
4002
+ }
4003
+ });
3718
4004
  addHandler('iOpa', hasKey('fillOpacity'), (reader, target) => {
3719
4005
  target.fillOpacity = (0, psdReader_1.readUint8)(reader) / 0xff;
3720
4006
  (0, psdReader_1.skipBytes)(reader, 3);