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
package/dist/bundle.js CHANGED
@@ -245,7 +245,7 @@ function readSampleBitmap(reader, brushEnd, id) {
245
245
  if (minDataSize > brushEnd - reader.offset) {
246
246
  throw new Error('Brush sample data out of bounds');
247
247
  }
248
- (0, psdReader_1.consumeMemory)(reader, w * h * (compression === 1 && bithDepth === 16 ? 3 : 1));
248
+ (0, psdReader_1.consumeMemory)(reader, w * h * (bithDepth === 16 ? 3 : 1));
249
249
  const alpha = new Uint8Array(w * h);
250
250
  if (bithDepth === 8) {
251
251
  if (compression === 0) {
@@ -259,21 +259,26 @@ function readSampleBitmap(reader, brushEnd, id) {
259
259
  }
260
260
  }
261
261
  else if (bithDepth === 16) {
262
+ const data = new Uint16Array(w * h);
262
263
  if (compression === 0) {
263
- for (let i = 0; i < alpha.byteLength; i++) {
264
- alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
264
+ for (let i = 0; i < data.length; i++) {
265
+ data[i] = (0, psdReader_1.readUint16)(reader);
265
266
  }
266
267
  }
267
268
  else if (compression === 1) {
268
- const data = new Uint16Array(w * h);
269
269
  (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data }, w, h, bithDepth, 1, [0], false);
270
- for (let i = 0; i < alpha.byteLength; i++) {
271
- alpha[i] = data[i] >> 8; // convert to 8bit values
272
- }
273
270
  }
274
271
  else {
275
272
  throw new Error('Invalid compression');
276
273
  }
274
+ // Photoshop uses 0-32768 range for 16bit values internally, use full 0-65535 range only if there are values outside of it
275
+ let max = 0;
276
+ for (let i = 0; i < data.length; i++)
277
+ max = Math.max(max, data[i]);
278
+ const scale = max > 32768 ? 255 / 65535 : 255 / 32768;
279
+ for (let i = 0; i < alpha.byteLength; i++) {
280
+ alpha[i] = Math.round(data[i] * scale); // convert to 8bit values
281
+ }
277
282
  }
278
283
  else {
279
284
  throw new Error('Invalid depth');
@@ -494,7 +499,7 @@ function parseBrush(brush) {
494
499
  return b;
495
500
  }
496
501
 
497
- },{"./descriptor":4,"./psdReader":13}],2:[function(require,module,exports){
502
+ },{"./descriptor":5,"./psdReader":14}],2:[function(require,module,exports){
498
503
  "use strict";
499
504
  Object.defineProperty(exports, "__esModule", { value: true });
500
505
  exports.booleanOperations = exports.infoHandlersMap = exports.infoHandlers = void 0;
@@ -605,11 +610,77 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
605
610
  (0, psdWriter_1.writeFloat32)(writer, (_d = text.bottom) !== null && _d !== void 0 ? _d : 0);
606
611
  // writeZeros(writer, 2);
607
612
  });
613
+ // type tool info from Photoshop 5.0 and 5.5, converted to regular text data (written as 'TySh')
614
+ addHandler('tySh', () => false, (reader, target, left) => {
615
+ if ((0, psdReader_1.readInt16)(reader) !== 1)
616
+ throw new Error(`Invalid tySh version`);
617
+ const transform = [];
618
+ for (let i = 0; i < 6; i++)
619
+ transform.push((0, psdReader_1.readFloat64)(reader));
620
+ if ((0, psdReader_1.readInt16)(reader) !== 6)
621
+ throw new Error(`Invalid tySh font version`);
622
+ const data = { transform, faces: [], styles: [], lines: [], color: { r: 0, g: 0, b: 0 }, antiAlias: false };
623
+ const facesCount = (0, psdReader_1.readInt16)(reader);
624
+ for (let i = 0; i < facesCount; i++) {
625
+ const mark = (0, psdReader_1.readInt16)(reader);
626
+ (0, psdReader_1.readInt32)(reader); // font type
627
+ const name = (0, psdReader_1.readPascalString)(reader, 1);
628
+ const familyName = (0, psdReader_1.readPascalString)(reader, 1);
629
+ const styleName = (0, psdReader_1.readPascalString)(reader, 1);
630
+ const script = (0, psdReader_1.readInt16)(reader);
631
+ const axesCount = (0, psdReader_1.readInt32)(reader);
632
+ if (axesCount < 0 || axesCount * 4 > left())
633
+ throw new Error(`Invalid tySh design axes count`);
634
+ (0, psdReader_1.skipBytes)(reader, axesCount * 4);
635
+ data.faces.push({ mark, name, familyName, styleName, script });
636
+ }
637
+ const stylesCount = (0, psdReader_1.readInt16)(reader);
638
+ for (let i = 0; i < stylesCount; i++) {
639
+ const mark = (0, psdReader_1.readInt16)(reader);
640
+ const faceMark = (0, psdReader_1.readInt16)(reader);
641
+ const size = (0, psdReader_1.readInt32)(reader);
642
+ const tracking = (0, psdReader_1.readInt32)(reader);
643
+ const kerning = (0, psdReader_1.readInt32)(reader);
644
+ const leading = (0, psdReader_1.readInt32)(reader);
645
+ const baselineShift = (0, psdReader_1.readInt32)(reader);
646
+ const autoKerning = !!(0, psdReader_1.readUint8)(reader);
647
+ (0, psdReader_1.readUint8)(reader); // rotate
648
+ data.styles.push({ mark, faceMark, size, tracking, kerning, leading, baselineShift, autoKerning });
649
+ }
650
+ (0, psdReader_1.readInt16)(reader); // type (0 = point, 1 = paragraph)
651
+ (0, psdReader_1.readInt32)(reader); // scaling factor
652
+ (0, psdReader_1.readInt32)(reader); // character count
653
+ (0, psdReader_1.readInt32)(reader); // horizontal placement
654
+ (0, psdReader_1.readInt32)(reader); // vertical placement
655
+ (0, psdReader_1.readInt32)(reader); // select start
656
+ (0, psdReader_1.readInt32)(reader); // select end
657
+ const linesCount = (0, psdReader_1.readInt16)(reader);
658
+ for (let i = 0; i < linesCount; i++) {
659
+ const charCount = (0, psdReader_1.readInt32)(reader);
660
+ const orientation = (0, psdReader_1.readInt16)(reader);
661
+ const alignment = (0, psdReader_1.readInt16)(reader);
662
+ if (charCount < 0 || charCount * 4 > left())
663
+ throw new Error(`Invalid tySh character count`);
664
+ const chars = [];
665
+ for (let j = 0; j < charCount; j++) {
666
+ const code = (0, psdReader_1.readUint16)(reader);
667
+ const style = (0, psdReader_1.readInt16)(reader);
668
+ chars.push({ code, style });
669
+ }
670
+ data.lines.push({ orientation, alignment, chars });
671
+ }
672
+ data.color = (0, psdReader_1.readColor)(reader);
673
+ data.antiAlias = !!(0, psdReader_1.readUint8)(reader);
674
+ if (!target.text)
675
+ target.text = (0, text_1.decodeLegacyTextData)(data);
676
+ (0, psdReader_1.skipBytes)(reader, left());
677
+ }, () => { });
608
678
  // vector fills
609
679
  addHandler('SoCo', target => target.vectorFill !== undefined && target.vectorStroke === undefined &&
610
- target.vectorFill.type === 'color', (reader, target) => {
680
+ target.vectorFill.type === 'color', (reader, target, left) => {
611
681
  const descriptor = (0, descriptor_1.readVersionAndDescriptor)(reader);
612
682
  target.vectorFill = (0, descriptor_1.parseVectorContent)(descriptor);
683
+ (0, psdReader_1.skipBytes)(reader, left());
613
684
  }, (writer, target) => {
614
685
  const { descriptor } = (0, descriptor_1.serializeVectorContent)(target.vectorFill);
615
686
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
@@ -898,10 +969,10 @@ addHandler('lmfx', target => target.effects !== undefined && !isGroupLayer(targe
898
969
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
899
970
  // console.log('READ', require('util').inspect(desc, false, 99, true));
900
971
  // discard if read in 'lrFX' or 'lfx2' section
901
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
972
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
902
973
  (0, psdReader_1.skipBytes)(reader, left());
903
- }, (writer, target, _, options) => {
904
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
974
+ }, (writer, target) => {
975
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
905
976
  // console.log('WRITE', require('util').inspect(desc, false, 99, true));
906
977
  (0, psdWriter_1.writeUint32)(writer, 0); // version
907
978
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
@@ -1036,6 +1107,58 @@ addHandler('lmgm', hasKey('layerMaskAsGlobalMask'), (reader, target) => {
1036
1107
  (0, psdWriter_1.writeUint8)(writer, target.layerMaskAsGlobalMask ? 1 : 0);
1037
1108
  (0, psdWriter_1.writeZeros)(writer, 3);
1038
1109
  });
1110
+ addHandler('vmgm', hasKey('vectorMaskAsGlobalMask'), (reader, target) => {
1111
+ target.vectorMaskAsGlobalMask = !!(0, psdReader_1.readUint8)(reader);
1112
+ (0, psdReader_1.skipBytes)(reader, 3);
1113
+ }, (writer, target) => {
1114
+ (0, psdWriter_1.writeUint8)(writer, target.vectorMaskAsGlobalMask ? 1 : 0);
1115
+ (0, psdWriter_1.writeZeros)(writer, 3);
1116
+ });
1117
+ addHandler('ffxi', hasKey('foreignEffectId'), (reader, target) => {
1118
+ target.foreignEffectId = (0, psdReader_1.readInt32)(reader);
1119
+ }, (writer, target) => {
1120
+ (0, psdWriter_1.writeInt32)(writer, target.foreignEffectId);
1121
+ });
1122
+ addHandler('shpa', hasKey('patternData'), (reader, target, left) => {
1123
+ if ((0, psdReader_1.readInt32)(reader) !== 0)
1124
+ throw new Error(`Invalid shpa version`);
1125
+ const count = (0, psdReader_1.readInt32)(reader);
1126
+ target.patternData = [];
1127
+ for (let i = 0; i < count && left() > 0; i++) {
1128
+ const signature = (0, psdReader_1.readSignature)(reader);
1129
+ const key = (0, psdReader_1.readSignature)(reader);
1130
+ const patternsCount = (0, psdReader_1.readInt32)(reader);
1131
+ const copyOnSheetDuplication = !!(0, psdReader_1.readUint8)(reader);
1132
+ (0, psdReader_1.skipBytes)(reader, 3);
1133
+ const patterns = [];
1134
+ for (let j = 0; j < patternsCount && left() > 0; j++) {
1135
+ const colorHandling = descriptor_1.patternColorHandling.decode('.' + (0, psdReader_1.readSignature)(reader));
1136
+ (0, psdReader_1.readPascalString)(reader, 1); // name
1137
+ const name = (0, psdReader_1.readUnicodeString)(reader);
1138
+ const id = (0, psdReader_1.readPascalString)(reader, 1);
1139
+ patterns.push({ colorHandling, name, id });
1140
+ }
1141
+ target.patternData.push({ signature, key, copyOnSheetDuplication, patterns });
1142
+ }
1143
+ (0, psdReader_1.skipBytes)(reader, left());
1144
+ }, (writer, target) => {
1145
+ const sets = target.patternData;
1146
+ (0, psdWriter_1.writeInt32)(writer, 0); // version
1147
+ (0, psdWriter_1.writeInt32)(writer, sets.length);
1148
+ for (const set of sets) {
1149
+ (0, psdWriter_1.writeSignature)(writer, set.signature);
1150
+ (0, psdWriter_1.writeSignature)(writer, set.key);
1151
+ (0, psdWriter_1.writeInt32)(writer, set.patterns.length);
1152
+ (0, psdWriter_1.writeUint8)(writer, set.copyOnSheetDuplication ? 1 : 0);
1153
+ (0, psdWriter_1.writeZeros)(writer, 3);
1154
+ for (const pattern of set.patterns) {
1155
+ (0, psdWriter_1.writeSignature)(writer, descriptor_1.patternColorHandling.encode(pattern.colorHandling).split('.')[1]);
1156
+ (0, psdWriter_1.writePascalString)(writer, pattern.name.replace(/[^\x20-\x7e]/g, '?'), 1);
1157
+ (0, psdWriter_1.writeUnicodeString)(writer, pattern.name);
1158
+ (0, psdWriter_1.writePascalString)(writer, pattern.id, 1);
1159
+ }
1160
+ }
1161
+ });
1039
1162
  addHandler('lspf', hasKey('protected'), (reader, target) => {
1040
1163
  const flags = (0, psdReader_1.readUint32)(reader);
1041
1164
  target.protected = {
@@ -1140,7 +1263,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
1140
1263
  if (f.FXRf)
1141
1264
  frame.referencePoint = (0, descriptor_1.horzVrtcToXY)(f.FXRf);
1142
1265
  if (f.Lefx)
1143
- frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, !!reader.logMissingFeatures);
1266
+ frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, reader);
1144
1267
  if (f.blendOptions && f.blendOptions.Opct)
1145
1268
  frame.opacity = (0, descriptor_1.parsePercent)(f.blendOptions.Opct);
1146
1269
  target.animationFrames.push(frame);
@@ -1171,7 +1294,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
1171
1294
  audioLevel: desc.audioLevel,
1172
1295
  };
1173
1296
  if (desc.trackList) {
1174
- timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, !!reader.logMissingFeatures);
1297
+ timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, reader);
1175
1298
  }
1176
1299
  target.timeline = timeline;
1177
1300
  // console.log('tmln:result', target.name, target.id, require('util').inspect(timeline, false, 99, true));
@@ -1253,7 +1376,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
1253
1376
  if (f.referencePoint)
1254
1377
  frame.FXRf = (0, descriptor_1.xyToHorzVrtc)(f.referencePoint);
1255
1378
  if (f.effects)
1256
- frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, false, hasMultiEffects(f.effects));
1379
+ frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, writer, hasMultiEffects(f.effects));
1257
1380
  if (f.opacity !== undefined)
1258
1381
  frame.blendOptions = { Opct: (0, descriptor_1.unitsPercentF)(f.opacity) };
1259
1382
  desc.LaSt.push(frame);
@@ -1293,7 +1416,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
1293
1416
  audioLevel: timeline.audioLevel,
1294
1417
  };
1295
1418
  if (timeline.tracks) {
1296
- desc.trackList = (0, descriptor_1.serializeTrackList)(timeline.tracks);
1419
+ desc.trackList = (0, descriptor_1.serializeTrackList)(timeline.tracks, writer);
1297
1420
  }
1298
1421
  desc.LyrI = getLayerId(target, options);
1299
1422
  // console.log('WRITE:tmln', target.name, target.id, require('util').inspect(desc, false, 99, true));
@@ -1672,6 +1795,86 @@ function pointToHrznVrtc(point) {
1672
1795
  Vrtc: (0, descriptor_1.unitsValue)(point.y, 'y'),
1673
1796
  };
1674
1797
  }
1798
+ // Camera Raw Filter setting paths (in CameraRawFilterSettings) and their descriptor keys
1799
+ const cameraRawColorKeys = [
1800
+ ['red', 'R'], ['orange', 'O'], ['yellow', 'Y'], ['green', 'G'], ['aqua', 'A'], ['blue', 'B'], ['purple', 'P'], ['magenta', 'M'],
1801
+ ];
1802
+ const cameraRawSettings = [
1803
+ ['version', 'CrVe'], ['processVersion', 'PrVN'], ['processVersionCode', 'PrVe'], ['whiteBalance', 'WBal'],
1804
+ ['temperature', 'Temp'], ['tint', 'Tint'], ['exposure', 'Ex12'], ['contrast', 'Cr12'], ['highlights', 'Hi12'],
1805
+ ['shadows', 'Sh12'], ['whites', 'Wh12'], ['blacks', 'Bk12'], ['texture', 'CrTx'], ['clarity', 'Cl12'],
1806
+ ['dehaze', 'Dhze'], ['vibrance', 'Vibr'], ['saturation', 'Strt'],
1807
+ ['parametricCurve.shadows', 'PC_S'], ['parametricCurve.darks', 'PC_D'], ['parametricCurve.lights', 'PC_L'],
1808
+ ['parametricCurve.highlights', 'PC_H'], ['parametricCurve.shadowSplit', 'PC_1'], ['parametricCurve.midtoneSplit', 'PC_2'],
1809
+ ['parametricCurve.highlightSplit', 'PC_3'],
1810
+ ['pointCurve.composite', 'Crv '], ['pointCurve.red', 'CrvR'], ['pointCurve.green', 'CrvG'], ['pointCurve.blue', 'CrvB'],
1811
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.hue.${name}`, `HA_${key}`]),
1812
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.saturation.${name}`, `SA_${key}`]),
1813
+ ...cameraRawColorKeys.map(([name, key]) => [`hsl.luminance.${name}`, `LA_${key}`]),
1814
+ ['colorGrading.shadows.hue', 'STSH'], ['colorGrading.shadows.saturation', 'STSS'], ['colorGrading.shadows.luminance', 'CgSL'],
1815
+ ['colorGrading.midtones.hue', 'CgMH'], ['colorGrading.midtones.saturation', 'CgMS'], ['colorGrading.midtones.luminance', 'CgML'],
1816
+ ['colorGrading.highlights.hue', 'STHH'], ['colorGrading.highlights.saturation', 'STHS'], ['colorGrading.highlights.luminance', 'CgHL'],
1817
+ ['colorGrading.global.hue', 'CgGH'], ['colorGrading.global.saturation', 'CgGS'], ['colorGrading.global.luminance', 'CgGL'],
1818
+ ['colorGrading.blending', 'CgBl'], ['colorGrading.balance', 'STB '],
1819
+ ['sharpening.amount', 'Shrp'], ['sharpening.radius', 'ShpR'], ['sharpening.detail', 'ShpD'], ['sharpening.masking', 'ShpM'],
1820
+ ['noiseReduction.luminance', 'LNR '], ['noiseReduction.luminanceDetail', 'LNRD'], ['noiseReduction.luminanceContrast', 'LNRC'],
1821
+ ['noiseReduction.color', 'CNR '], ['noiseReduction.colorDetail', 'CNRD'], ['noiseReduction.colorSmoothness', 'CNRS'],
1822
+ ['grain.amount', 'GRNA'], ['grain.size', 'GRNS'], ['grain.roughness', 'GRNF'],
1823
+ ['postCropVignette.amount', 'PCVA'], ['postCropVignette.midpoint', 'PCVM'], ['postCropVignette.feather', 'PCVF'],
1824
+ ['postCropVignette.roundness', 'PCVR'],
1825
+ ];
1826
+ const cameraRawCurveKeys = ['Crv ', 'CrvR', 'CrvG', 'CrvB'];
1827
+ const cameraRawFilterID = 2783;
1828
+ function parseCameraRawSettings(desc, reader) {
1829
+ var _a;
1830
+ const settings = {};
1831
+ for (const [path, key] of cameraRawSettings) {
1832
+ let value = desc[key];
1833
+ if (value === undefined)
1834
+ continue;
1835
+ if (key === 'WBal') {
1836
+ value = value.split('.')[1];
1837
+ }
1838
+ else if (cameraRawCurveKeys.includes(key)) {
1839
+ const values = value;
1840
+ value = [];
1841
+ for (let i = 0; i + 1 < values.length; i += 2)
1842
+ value.push({ input: values[i], output: values[i + 1] });
1843
+ }
1844
+ const parts = path.split('.');
1845
+ let target = settings;
1846
+ for (let i = 0; i < parts.length - 1; i++)
1847
+ target = target[parts[i]] = (_a = target[parts[i]]) !== null && _a !== void 0 ? _a : {};
1848
+ target[parts[parts.length - 1]] = value;
1849
+ }
1850
+ for (const key of Object.keys(desc)) {
1851
+ if (key !== '_name' && key !== '_classID' && !cameraRawSettings.some(s => s[1] === key)) {
1852
+ reader.logMissingFeatures && reader.log(`Unhandled Camera Raw Filter setting: ${key}`);
1853
+ }
1854
+ }
1855
+ return settings;
1856
+ }
1857
+ function serializeCameraRawSettings(settings) {
1858
+ const desc = { _name: '', _classID: descriptor_1.cameraRawFilterClassID };
1859
+ for (const [path, key] of cameraRawSettings) {
1860
+ let value = settings;
1861
+ for (const part of path.split('.'))
1862
+ value = value === null || value === void 0 ? void 0 : value[part];
1863
+ if (value === undefined)
1864
+ continue;
1865
+ if (key === 'WBal') {
1866
+ value = `WBal.${value}`;
1867
+ }
1868
+ else if (cameraRawCurveKeys.includes(key)) {
1869
+ value = value.flatMap(p => [Math.round(p.input), Math.round(p.output)]);
1870
+ }
1871
+ else if (typeof value === 'number' && key !== 'Ex12' && key !== 'ShpR') {
1872
+ value = Math.round(value);
1873
+ }
1874
+ desc[key] = value;
1875
+ }
1876
+ return desc;
1877
+ }
1675
1878
  function parseFilterFXItem(f, reader) {
1676
1879
  const base = {
1677
1880
  name: f['Nm '],
@@ -1682,6 +1885,9 @@ function parseFilterFXItem(f, reader) {
1682
1885
  foregroundColor: (0, descriptor_1.parseColor)(f.FrgC),
1683
1886
  backgroundColor: (0, descriptor_1.parseColor)(f.BckC),
1684
1887
  };
1888
+ if ('Fltr' in f && f.Fltr._classID === descriptor_1.cameraRawFilterClassID) {
1889
+ return Object.assign(Object.assign({}, base), { type: 'camera raw', filter: parseCameraRawSettings(f.Fltr, reader) });
1890
+ }
1685
1891
  if ('Fltr' in f) {
1686
1892
  switch (f.Fltr._classID) {
1687
1893
  case 'boxblur': return Object.assign(Object.assign({}, base), { type: 'box blur', filter: {
@@ -2580,6 +2786,7 @@ function serializeFilterFXItem(f) {
2580
2786
  return adjustment;
2581
2787
  }),
2582
2788
  } : {})), filterID: 1282829427 });
2789
+ case 'camera raw': return Object.assign(Object.assign({}, base), { Fltr: serializeCameraRawSettings(f.filter), filterID: cameraRawFilterID });
2583
2790
  case 'brightness/contrast': return Object.assign(Object.assign({}, base), { Fltr: {
2584
2791
  _name: 'Brightness/Contrast',
2585
2792
  _classID: 'BrgC',
@@ -2805,31 +3012,23 @@ addHandler('LMsk', hasKey('userMask'), (reader, target) => {
2805
3012
  (0, psdWriter_1.writeUint8)(writer, 128);
2806
3013
  (0, psdWriter_1.writeZeros)(writer, 1);
2807
3014
  });
2808
- if (helpers_1.MOCK_HANDLERS) {
2809
- addHandler('Patt', target => target._Patt !== undefined, (reader, target, left) => {
2810
- // console.log('additional info: Patt');
2811
- target._Patt = (0, psdReader_1.readBytes)(reader, left());
2812
- }, (writer, target) => false && (0, psdWriter_1.writeBytes)(writer, target._Patt));
2813
- }
2814
- else {
2815
- addHandler('Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2816
- // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
2817
- target => !!(target.patterns && target.patterns.length > 0), (reader, target, left) => {
2818
- while (left() > 0) {
2819
- const pattern = (0, psdReader_1.readPatternSafe)(reader);
2820
- if (!pattern)
2821
- continue;
2822
- if (target.patterns === undefined)
2823
- target.patterns = [];
2824
- target.patterns.push(pattern);
2825
- }
2826
- }, (writer, target, _, _options) => {
2827
- const patterns = target.patterns || [];
2828
- for (const pattern of patterns) {
2829
- (0, psdWriter_1.writePattern)(writer, pattern);
2830
- }
2831
- });
2832
- }
3015
+ addHandler('Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
3016
+ // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
3017
+ target => !!(target.patterns && target.patterns.length > 0), (reader, target, left) => {
3018
+ while (left() > 0) {
3019
+ const pattern = (0, psdReader_1.readPatternSafe)(reader);
3020
+ if (!pattern)
3021
+ continue;
3022
+ if (target.patterns === undefined)
3023
+ target.patterns = [];
3024
+ target.patterns.push(pattern);
3025
+ }
3026
+ }, (writer, target, _, _options) => {
3027
+ const patterns = target.patterns || [];
3028
+ for (const pattern of patterns) {
3029
+ (0, psdWriter_1.writePattern)(writer, pattern);
3030
+ }
3031
+ });
2833
3032
  addHandlerAlias('Pat2', 'Patt');
2834
3033
  addHandlerAlias('Pat3', 'Patt');
2835
3034
  /*
@@ -3221,10 +3420,10 @@ target => target.effects !== undefined && isGroupLayer(target), (reader, target,
3221
3420
  if (version !== 0)
3222
3421
  throw new Error(`Invalid lfxs version`);
3223
3422
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
3224
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
3423
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
3225
3424
  (0, psdReader_1.skipBytes)(reader, left());
3226
- }, (writer, target, _, options) => {
3227
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
3425
+ }, (writer, target) => {
3426
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
3228
3427
  (0, psdWriter_1.writeUint32)(writer, 0); // version
3229
3428
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
3230
3429
  });
@@ -3279,11 +3478,19 @@ addHandler('levl', adjustmentType('levels'), (reader, target, left) => {
3279
3478
  channels.push(readLevelsChannel(reader));
3280
3479
  }
3281
3480
  if (left() >= 8) {
3282
- if ((0, psdReader_1.readSignature)(reader) !== 'Lvls')
3283
- throw new Error(`Invalid levl signature`);
3284
- if ((0, psdReader_1.readUint16)(reader) !== 3)
3285
- throw new Error(`Invalid levl version`);
3286
- const totalChannelRecords = (0, psdReader_1.readUint16)(reader);
3481
+ const signature = (0, psdReader_1.readSignature)(reader);
3482
+ let totalChannelRecords;
3483
+ if (signature === 'ls\x00\x03') {
3484
+ // Clip Studio Paint writes 'ls' instead of 'Lvls' signature (version is part of the read signature)
3485
+ totalChannelRecords = (0, psdReader_1.readUint16)(reader);
3486
+ }
3487
+ else {
3488
+ if (signature !== 'Lvls')
3489
+ throw new Error(`Invalid levl signature`);
3490
+ if ((0, psdReader_1.readUint16)(reader) !== 3)
3491
+ throw new Error(`Invalid levl version`);
3492
+ totalChannelRecords = (0, psdReader_1.readUint16)(reader);
3493
+ }
3287
3494
  while (channels.length < totalChannelRecords && left() >= 10) {
3288
3495
  channels.push(readLevelsChannel(reader));
3289
3496
  }
@@ -3324,58 +3531,78 @@ function writeCurveChannel(writer, channel) {
3324
3531
  }
3325
3532
  }
3326
3533
  addHandler('curv', adjustmentType('curves'), (reader, target, left) => {
3327
- (0, psdReader_1.readUint8)(reader);
3328
- if ((0, psdReader_1.readUint16)(reader) !== 1)
3534
+ const isMap = !!(0, psdReader_1.readUint8)(reader); // curves drawn with pencil tool (lookup tables instead of points)
3535
+ const version = (0, psdReader_1.readUint16)(reader);
3536
+ if (version !== 1 && version !== 4)
3329
3537
  throw new Error('Invalid curv version');
3330
- (0, psdReader_1.readUint16)(reader);
3331
- const channelsMask = (0, psdReader_1.readUint16)(reader);
3538
+ const countOrMask = (0, psdReader_1.readUint32)(reader);
3332
3539
  const channels = [];
3333
- for (let i = 0; i < 16; i++) {
3334
- if (channelsMask & (1 << i)) {
3335
- while (channels.length < i)
3540
+ const readChannel = () => isMap ? Array.from((0, psdReader_1.readBytes)(reader, 256)) : readCurveChannel(reader);
3541
+ if (version === 1) {
3542
+ for (let i = 0; i < 32; i++) {
3543
+ if (countOrMask & (1 << i)) {
3544
+ while (channels.length < i)
3545
+ channels.push([]);
3546
+ channels.push(readChannel());
3547
+ }
3548
+ }
3549
+ }
3550
+ else {
3551
+ if (countOrMask > 64)
3552
+ throw new Error('Invalid curv channel count');
3553
+ for (let i = 0; i < countOrMask; i++)
3554
+ channels.push(readChannel());
3555
+ }
3556
+ // extra section stores curves for all channels (including ones that don't fit in the mask)
3557
+ if (version === 1 && left() >= 10 && (0, psdReader_1.readSignature)(reader) === 'Crv ') {
3558
+ (0, psdReader_1.readUint16)(reader); // version
3559
+ const count = (0, psdReader_1.readUint32)(reader);
3560
+ for (let i = 0; i < count && left() >= 2; i++) {
3561
+ const index = (0, psdReader_1.readUint16)(reader);
3562
+ const channel = readChannel();
3563
+ while (channels.length < index)
3336
3564
  channels.push([]);
3337
- channels.push(readCurveChannel(reader));
3338
- }
3339
- }
3340
- target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'curves', channels });
3341
- // ignoring, duplicate information
3342
- // checkSignature(reader, 'Crv ');
3343
- // const cVersion = readUint16(reader);
3344
- // readUint16(reader);
3345
- // const channelCount = readUint16(reader);
3346
- // for (let i = 0; i < channelCount; i++) {
3347
- // const index = readUint16(reader);
3348
- // const nodes = readUint16(reader);
3349
- // for (let j = 0; j < nodes; j++) {
3350
- // const output = readInt16(reader);
3351
- // const input = readInt16(reader);
3352
- // }
3353
- // }
3565
+ channels[index] = channel;
3566
+ }
3567
+ }
3568
+ target.adjustment = Object.assign(Object.assign(Object.assign({}, target.adjustment), { type: 'curves' }), (isMap ? { values: channels } : { channels: channels }));
3354
3569
  (0, psdReader_1.skipBytes)(reader, left());
3355
3570
  }, (writer, target) => {
3356
3571
  var _a;
3357
- const channels = (target.adjustment.channels || []).slice(0, 16);
3572
+ const adjustment = target.adjustment;
3573
+ const isMap = !!adjustment.values;
3574
+ const channels = (isMap ? adjustment.values : adjustment.channels) || [];
3358
3575
  const used = [];
3359
3576
  let channelsMask = 0;
3360
3577
  for (let i = 0; i < channels.length; i++) {
3361
3578
  if ((_a = channels[i]) === null || _a === void 0 ? void 0 : _a.length) {
3362
- channelsMask |= 1 << i;
3579
+ if (i < 32)
3580
+ channelsMask |= 1 << i;
3363
3581
  used.push(i);
3364
3582
  }
3365
3583
  }
3366
- (0, psdWriter_1.writeUint8)(writer, 0);
3584
+ const writeChannel = (channel) => {
3585
+ var _a;
3586
+ if (isMap) {
3587
+ for (let i = 0; i < 256; i++)
3588
+ (0, psdWriter_1.writeUint8)(writer, (0, helpers_1.clamp)(Math.round((_a = channel[i]) !== null && _a !== void 0 ? _a : i), 0, 255));
3589
+ }
3590
+ else {
3591
+ writeCurveChannel(writer, channel);
3592
+ }
3593
+ };
3594
+ (0, psdWriter_1.writeUint8)(writer, isMap ? 1 : 0);
3367
3595
  (0, psdWriter_1.writeUint16)(writer, 1); // version
3368
- (0, psdWriter_1.writeUint16)(writer, 0);
3369
- (0, psdWriter_1.writeUint16)(writer, channelsMask);
3596
+ (0, psdWriter_1.writeUint32)(writer, channelsMask >>> 0);
3370
3597
  for (const i of used)
3371
- writeCurveChannel(writer, channels[i]);
3598
+ if (i < 32)
3599
+ writeChannel(channels[i]);
3372
3600
  (0, psdWriter_1.writeSignature)(writer, 'Crv ');
3373
3601
  (0, psdWriter_1.writeUint16)(writer, 4); // version
3374
- (0, psdWriter_1.writeUint16)(writer, 0);
3375
- (0, psdWriter_1.writeUint16)(writer, used.length);
3602
+ (0, psdWriter_1.writeUint32)(writer, used.length);
3376
3603
  for (const i of used) {
3377
3604
  (0, psdWriter_1.writeUint16)(writer, i);
3378
- writeCurveChannel(writer, channels[i]);
3605
+ writeChannel(channels[i]);
3379
3606
  }
3380
3607
  });
3381
3608
  addHandler('expA', adjustmentType('exposure'), (reader, target, left) => {
@@ -4087,6 +4314,10 @@ addHandler('FEid', hasKey('filterEffectsMasks'), (reader, target, leftBytes) =>
4087
4314
  }
4088
4315
  });
4089
4316
  addHandlerAlias('FXid', 'FEid');
4317
+ addHandlerAlias('FELS', 'FEid'); // filter effects 3
4318
+ addHandlerAlias('hue ', 'hue2'); // old hue/saturation (Photoshop 4.0), same structure as 'hue2'
4319
+ addHandlerAlias('plLd', 'PlLd'); // old placed layer key
4320
+ addHandlerAlias('abdd', 'artb'); // artboard data 3
4090
4321
  addHandler('FMsk', hasKey('filterMask'), (reader, target) => {
4091
4322
  target.filterMask = {
4092
4323
  colorSpace: (0, psdReader_1.readColor)(reader),
@@ -4147,10 +4378,10 @@ addHandler('lfx2', target => target.effects !== undefined && !isGroupLayer(targe
4147
4378
  const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
4148
4379
  // console.log('READ', require('util').inspect(desc, false, 99, true));
4149
4380
  // discard if read in 'lrFX' section ('lmfx' and 'lfx2' are never stored together)
4150
- target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
4381
+ target.effects = (0, descriptor_1.parseEffects)(desc, reader);
4151
4382
  (0, psdReader_1.skipBytes)(reader, left());
4152
- }, (writer, target, _, options) => {
4153
- const desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
4383
+ }, (writer, target) => {
4384
+ const desc = (0, descriptor_1.serializeEffects)(target.effects, writer, true);
4154
4385
  // console.log('WRITE', require('util').inspect(desc, false, 99, true));
4155
4386
  (0, psdWriter_1.writeUint32)(writer, 0); // version
4156
4387
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
@@ -4212,6 +4443,66 @@ addHandler('extn', target => target.generatorSettings !== undefined && isDocumen
4212
4443
  }, (writer, target) => {
4213
4444
  (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', serializeGeneratorSettings(target.generatorSettings));
4214
4445
  });
4446
+ // generator settings stored by older versions of Photoshop (written back in 'shmd' or 'extn' section)
4447
+ addHandler('extd', () => false, (reader, target, left) => {
4448
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
4449
+ if (desc.generatorSettings && target.generatorSettings === undefined) {
4450
+ target.generatorSettings = parseGeneratorSettings(desc.generatorSettings);
4451
+ }
4452
+ (0, psdReader_1.skipBytes)(reader, left());
4453
+ }, () => { });
4454
+ addHandler('frgb', // frame tool group
4455
+ hasKey('framedGroup'), (reader, target, left) => {
4456
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
4457
+ const rect = desc.framedGroupRect;
4458
+ target.framedGroup = {
4459
+ rect: { top: rect['Top '], left: rect.Left, bottom: rect.Btom, right: rect.Rght },
4460
+ type: desc.framedGroupType,
4461
+ };
4462
+ if (desc.LockPPI !== undefined)
4463
+ target.framedGroup.lockPPI = desc.LockPPI;
4464
+ if (desc.PreferredResolution !== undefined)
4465
+ target.framedGroup.preferredResolution = desc.PreferredResolution;
4466
+ if (desc.SavedIteratedName !== undefined)
4467
+ target.framedGroup.savedIteratedName = desc.SavedIteratedName;
4468
+ (0, psdReader_1.skipBytes)(reader, left());
4469
+ }, (writer, target) => {
4470
+ const group = target.framedGroup;
4471
+ const rect = group.rect;
4472
+ const desc = {
4473
+ framedGroupRect: { _name: '', _classID: 'classFloatRect', 'Top ': rect.top, Left: rect.left, Btom: rect.bottom, Rght: rect.right },
4474
+ framedGroupType: group.type,
4475
+ };
4476
+ if (group.lockPPI !== undefined)
4477
+ desc.LockPPI = group.lockPPI;
4478
+ if (group.preferredResolution !== undefined)
4479
+ desc.PreferredResolution = group.preferredResolution;
4480
+ if (group.savedIteratedName !== undefined)
4481
+ desc.SavedIteratedName = group.savedIteratedName;
4482
+ (0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'framedGroup', desc);
4483
+ });
4484
+ addHandler('anFX', hasKey('animationEffects'), (reader, target, left) => {
4485
+ target.animationEffects = (0, psdReader_1.readBytes)(reader, left());
4486
+ }, (writer, target) => {
4487
+ (0, psdWriter_1.writeBytes)(writer, target.animationEffects);
4488
+ });
4489
+ addHandler('PxSD', // pixel source data 2 (video layer frames)
4490
+ hasKey('pixelSourceData'), (reader, target, left) => {
4491
+ target.pixelSourceData = [];
4492
+ while (left() >= 8) {
4493
+ const length = readLength64(reader);
4494
+ if (length > left())
4495
+ throw new Error('Invalid PxSD data length');
4496
+ target.pixelSourceData.push((0, psdReader_1.readBytes)(reader, length));
4497
+ }
4498
+ (0, psdReader_1.skipBytes)(reader, left());
4499
+ }, (writer, target) => {
4500
+ for (const data of target.pixelSourceData) {
4501
+ (0, psdWriter_1.writeUint32)(writer, 0);
4502
+ (0, psdWriter_1.writeUint32)(writer, data.byteLength);
4503
+ (0, psdWriter_1.writeBytes)(writer, data);
4504
+ }
4505
+ });
4215
4506
  addHandler('iOpa', hasKey('fillOpacity'), (reader, target) => {
4216
4507
  target.fillOpacity = (0, psdReader_1.readUint8)(reader) / 0xff;
4217
4508
  (0, psdReader_1.skipBytes)(reader, 3);
@@ -4237,7 +4528,92 @@ addHandler('tsly', hasKey('transparencyShapesLayer'), (reader, target) => {
4237
4528
  (0, psdWriter_1.writeZeros)(writer, 3);
4238
4529
  });
4239
4530
 
4240
- },{"./descriptor":4,"./effectsHelpers":5,"./engineData":6,"./engineData2":7,"./helpers":8,"./psdReader":13,"./psdWriter":14,"./text":15,"base64-js":17}],3:[function(require,module,exports){
4531
+ },{"./descriptor":5,"./effectsHelpers":6,"./engineData":7,"./engineData2":8,"./helpers":9,"./psdReader":14,"./psdWriter":15,"./text":16,"base64-js":18}],3:[function(require,module,exports){
4532
+ "use strict";
4533
+ Object.defineProperty(exports, "__esModule", { value: true });
4534
+ exports.readAse = readAse;
4535
+ const psdReader_1 = require("./psdReader");
4536
+ function readAse(buffer, options = {}) {
4537
+ const reader = (0, psdReader_1.createReader)(buffer.buffer, buffer.byteOffset, buffer.byteLength);
4538
+ const signature = (0, psdReader_1.readSignature)(reader); // ASEF
4539
+ if (signature !== 'ASEF')
4540
+ throw new Error('Invalid signature');
4541
+ const versionMajor = (0, psdReader_1.readUint16)(reader); // 1
4542
+ (0, psdReader_1.readUint16)(reader); // minor version: 0
4543
+ if (versionMajor !== 1)
4544
+ throw new Error('Invalid version');
4545
+ const blocksCount = (0, psdReader_1.readUint32)(reader);
4546
+ const ase = { colors: [] };
4547
+ let group = ase;
4548
+ for (let i = 0; i < blocksCount && reader.offset + 6 <= reader.view.byteLength; i++) {
4549
+ const type = (0, psdReader_1.readUint16)(reader);
4550
+ const length = (0, psdReader_1.readUint32)(reader);
4551
+ const end = Math.min(reader.offset + length, reader.view.byteLength);
4552
+ // block reader, so invalid lengths can't make us read data of following blocks
4553
+ const block = (0, psdReader_1.createReader)(reader.view.buffer, reader.view.byteOffset + reader.offset, end - reader.offset);
4554
+ try {
4555
+ switch (type) {
4556
+ case 0x0001: { // color
4557
+ const color = readAseColor(block);
4558
+ if (color) {
4559
+ group.colors.push(color);
4560
+ }
4561
+ else {
4562
+ if (options.throwForMissingFeatures)
4563
+ throw new Error('Unsupported color mode');
4564
+ options.logMissingFeatures && reader.log('Skipped color with unsupported color mode');
4565
+ }
4566
+ break;
4567
+ }
4568
+ case 0xC001: { // group start
4569
+ const nameLength = (0, psdReader_1.readUint16)(block);
4570
+ const name = (0, psdReader_1.readUnicodeStringWithLength)(block, nameLength);
4571
+ ase.colors.push(group = { name, colors: [] });
4572
+ break;
4573
+ }
4574
+ case 0xC002: // group end
4575
+ group = ase;
4576
+ break;
4577
+ default:
4578
+ if (options.throwForMissingFeatures)
4579
+ throw new Error(`Invalid block type: ${type}`);
4580
+ options.logMissingFeatures && reader.log(`Skipped unknown block type: ${type}`);
4581
+ }
4582
+ }
4583
+ catch (e) {
4584
+ if (options.throwForMissingFeatures)
4585
+ throw e;
4586
+ options.logMissingFeatures && reader.log(`Skipped invalid block: ${e.message}`);
4587
+ }
4588
+ reader.offset = end;
4589
+ }
4590
+ return ase;
4591
+ }
4592
+ function readAseColor(reader) {
4593
+ const nameLength = (0, psdReader_1.readUint16)(reader);
4594
+ const name = (0, psdReader_1.readUnicodeStringWithLength)(reader, nameLength);
4595
+ const colorMode = (0, psdReader_1.readSignature)(reader);
4596
+ // NaN and infinite values are replaced with 0
4597
+ const value = () => {
4598
+ const v = (0, psdReader_1.readFloat32)(reader);
4599
+ return isFinite(v) ? v : 0;
4600
+ };
4601
+ // color type is sometimes missing, unknown types are treated as process (normal) colors
4602
+ const colorType = () => {
4603
+ const index = reader.offset + 2 <= reader.view.byteLength ? (0, psdReader_1.readUint16)(reader) : 2;
4604
+ return colorTypes[index] || 'normal';
4605
+ };
4606
+ switch (colorMode) {
4607
+ case 'RGB ': return { name, color: { r: value(), g: value(), b: value(), type: colorType() } };
4608
+ case 'CMYK': return { name, color: { c: value(), m: value(), y: value(), k: value(), type: colorType() } };
4609
+ case 'Gray': return { name, color: { k: value(), type: colorType() } };
4610
+ case 'LAB ': return { name, color: { l: value(), a: value(), b: value(), type: colorType() } };
4611
+ default: return undefined;
4612
+ }
4613
+ }
4614
+ const colorTypes = ['global', 'spot', 'normal'];
4615
+
4616
+ },{"./psdReader":14}],4:[function(require,module,exports){
4241
4617
  "use strict";
4242
4618
  Object.defineProperty(exports, "__esModule", { value: true });
4243
4619
  exports.readCsh = readCsh;
@@ -4274,7 +4650,7 @@ function readCsh(buffer) {
4274
4650
  return csh;
4275
4651
  }
4276
4652
 
4277
- },{"./additionalInfo":2,"./psdReader":13}],4:[function(require,module,exports){
4653
+ },{"./additionalInfo":2,"./psdReader":14}],5:[function(require,module,exports){
4278
4654
  "use strict";
4279
4655
  var __rest = (this && this.__rest) || function (s, e) {
4280
4656
  var t = {};
@@ -4288,9 +4664,8 @@ var __rest = (this && this.__rest) || function (s, e) {
4288
4664
  return t;
4289
4665
  };
4290
4666
  Object.defineProperty(exports, "__esModule", { value: true });
4291
- exports.Drct = exports.WndM = exports.CntE = exports.FlCl = exports.ExtR = exports.ExtT = exports.DfsM = exports.blurType = exports.Lns = exports.MztT = exports.Chnl = exports.Dstr = exports.ZZTy = exports.Wvtp = exports.SphM = exports.RplS = exports.Cnvr = exports.UndA = exports.DspM = exports.SmBQ = exports.SmBM = exports.BlrQ = exports.BlrM = exports.strokeStyleLineAlignment = exports.strokeStyleLineJoinType = exports.strokeStyleLineCapType = exports.ESliceBGColorType = exports.ESliceOrigin = exports.ESliceVertAlign = exports.ESliceHorzAlign = exports.ESliceType = exports.FrFl = exports.FStl = exports.ClrS = exports.Clry = exports.gradientInterpolationMethodType = exports.stdTrackID = exports.animInterpStyleEnum = exports.GrdT = exports.IGSr = exports.BETE = exports.BESs = exports.bvlT = exports.BESl = exports.BlnM = exports.warpStyle = exports.Annt = exports.Ornt = exports.textGridding = exports.outputSettingsRoot = void 0;
4292
- exports.presetKindType = exports.prjM = exports.FlMd = exports.IntC = exports.IntE = void 0;
4293
- exports.setLogErrors = setLogErrors;
4667
+ exports.CntE = exports.FlCl = exports.ExtR = exports.ExtT = exports.DfsM = exports.blurType = exports.Lns = exports.MztT = exports.Chnl = exports.Dstr = exports.ZZTy = exports.Wvtp = exports.SphM = exports.RplS = exports.Cnvr = exports.UndA = exports.DspM = exports.SmBQ = exports.SmBM = exports.BlrQ = exports.BlrM = exports.strokeStyleLineAlignment = exports.strokeStyleLineJoinType = exports.strokeStyleLineCapType = exports.ESliceBGColorType = exports.ESliceOrigin = exports.ESliceVertAlign = exports.ESliceHorzAlign = exports.ESliceType = exports.FrFl = exports.FStl = exports.ClrS = exports.Clry = exports.gradientInterpolationMethodType = exports.stdTrackID = exports.animInterpStyleEnum = exports.GrdT = exports.IGSr = exports.BETE = exports.BESs = exports.bvlT = exports.BESl = exports.BlnM = exports.warpStyle = exports.Annt = exports.Ornt = exports.textGridding = exports.outputSettingsRoot = exports.cameraRawFilterKeyTypes = exports.cameraRawFilterClassID = void 0;
4668
+ exports.patternColorHandling = exports.presetKindType = exports.prjM = exports.FlMd = exports.IntC = exports.IntE = exports.Drct = exports.WndM = void 0;
4294
4669
  exports.readAsciiStringOrClassId = readAsciiStringOrClassId;
4295
4670
  exports.writeAsciiStringOrClassId = writeAsciiStringOrClassId;
4296
4671
  exports.readDescriptorStructure = readDescriptorStructure;
@@ -4344,10 +4719,6 @@ const unitsMap = {
4344
4719
  'RrCm': 'Centimeters',
4345
4720
  };
4346
4721
  const unitsMapRev = revMap(unitsMap);
4347
- let logErrors = false;
4348
- function setLogErrors(value) {
4349
- logErrors = value;
4350
- }
4351
4722
  function makeType(name, classID) {
4352
4723
  return { name, classID };
4353
4724
  }
@@ -4393,6 +4764,7 @@ const fieldToExtType = {
4393
4764
  psVersion: nullType,
4394
4765
  docDefaultNewArtboardBackgroundColor: makeType('', 'RGBC'),
4395
4766
  artboardRect: makeType('', 'classFloatRect'),
4767
+ framedGroupRect: makeType('', 'classFloatRect'),
4396
4768
  keyOriginRRectRadii: makeType('', 'radii'),
4397
4769
  keyOriginBoxCorners: nullType,
4398
4770
  rectangleCornerA: makeType('', 'Pnt '),
@@ -4478,7 +4850,7 @@ const fieldToArrayExtType = {
4478
4850
  const typeToField = {
4479
4851
  'TEXT': [
4480
4852
  'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName', 'exportOption', 'scaleSettings',
4481
- 'BackgroundImagePath', 'ImageSubfolderName',
4853
+ 'BackgroundImagePath', 'ImageSubfolderName', 'SavedIteratedName',
4482
4854
  'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
4483
4855
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
4484
4856
  'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath', 'Bk ', 'pathUnicodeName',
@@ -4505,7 +4877,7 @@ const typeToField = {
4505
4877
  'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
4506
4878
  'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
4507
4879
  'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
4508
- 'pixelSourceType',
4880
+ 'pixelSourceType', 'framedGroupType',
4509
4881
  ],
4510
4882
  'enum': [
4511
4883
  'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
@@ -4529,7 +4901,7 @@ const typeToField = {
4529
4901
  'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
4530
4902
  'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
4531
4903
  'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
4532
- 'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn',
4904
+ 'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn', 'LockPPI',
4533
4905
  ],
4534
4906
  'doub': [
4535
4907
  'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght', 'Gmm ',
@@ -4537,7 +4909,7 @@ const typeToField = {
4537
4909
  'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
4538
4910
  'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
4539
4911
  'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3',
4540
- 'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity',
4912
+ 'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity', 'PreferredResolution',
4541
4913
  ],
4542
4914
  'UntF': [
4543
4915
  'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
@@ -4566,6 +4938,12 @@ const channels = [
4566
4938
  // color classes whose channel values are written as doubles ('GRYC' and 'LABC' are kept for backwards compatibility)
4567
4939
  const doubleColorClasses = ['Grsc', 'LbCl', 'GRYC', 'LABC'];
4568
4940
  // fallback for unknown keys, based on the type of the value
4941
+ exports.cameraRawFilterClassID = 'Adobe Camera Raw Filter';
4942
+ // types of Camera Raw Filter settings (keys clash with other descriptors so they're typed by class)
4943
+ exports.cameraRawFilterKeyTypes = {
4944
+ CrVe: 'TEXT', PrVN: 'long', PrVe: 'long', WBal: 'enum', Ex12: 'doub', ShpR: 'doub',
4945
+ 'Crv ': 'VlLs', CrvR: 'VlLs', CrvG: 'VlLs', CrvB: 'VlLs',
4946
+ };
4569
4947
  function guessOSType(value) {
4570
4948
  if (typeof value === 'boolean')
4571
4949
  return 'bool';
@@ -4741,8 +5119,9 @@ function readDescriptorStructure(reader, includeClass) {
4741
5119
  }
4742
5120
  exports.outputSettingsRoot = 'outputSettings';
4743
5121
  function writeDescriptorStructure(writer, name, classId, value, root) {
4744
- if (logErrors && !classId)
4745
- console.log('Missing classId for: ', name, classId, value);
5122
+ var _a;
5123
+ if (writer.logMissingFeatures && !classId)
5124
+ writer.log('Missing classId for: ', name, classId, value);
4746
5125
  // write class structure
4747
5126
  (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
4748
5127
  if (root === exports.outputSettingsRoot && classId === 'null') {
@@ -4760,6 +5139,10 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
4760
5139
  let type = getTypeByKey(key, value[key], root, value);
4761
5140
  let childRoot = root;
4762
5141
  let extType = fieldToExtType[key];
5142
+ if (classId === exports.cameraRawFilterClassID) {
5143
+ type = (_a = exports.cameraRawFilterKeyTypes[key]) !== null && _a !== void 0 ? _a : 'long'; // other settings are integer levels
5144
+ childRoot = exports.cameraRawFilterClassID; // lists (curves) contain integer levels
5145
+ }
4763
5146
  if (key === 'bounds' && root === 'text') {
4764
5147
  extType = makeType('', 'bounds');
4765
5148
  }
@@ -4856,7 +5239,7 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
4856
5239
  extType = makeType('', 'patternLayer');
4857
5240
  }
4858
5241
  else {
4859
- logErrors && console.log('Invalid strokeStyleContent value', value[key]);
5242
+ writer.logMissingFeatures && writer.log('Invalid strokeStyleContent value', value[key]);
4860
5243
  }
4861
5244
  }
4862
5245
  else if (key === 'bounds' && root === 'quiltWarp') {
@@ -4878,8 +5261,8 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
4878
5261
  writeAsciiStringOrClassId(writer, key);
4879
5262
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
4880
5263
  writeOSType(writer, type || 'long', value[key], key, extType, childRoot);
4881
- if (logErrors && !type)
4882
- console.log(`Missing descriptor field type for: '${key}' in`, value);
5264
+ if (writer.logMissingFeatures && !type)
5265
+ writer.log(`Missing descriptor field type for: '${key}' in`, value);
4883
5266
  }
4884
5267
  }
4885
5268
  function readOSType(reader, type, includeClass) {
@@ -5000,11 +5383,11 @@ function writeOSType(writer, type, value, key, extType, root) {
5000
5383
  throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
5001
5384
  (0, psdWriter_1.writeInt32)(writer, value.length);
5002
5385
  for (let i = 0; i < value.length; i++) {
5003
- const type = (_a = fieldToArrayType[key]) !== null && _a !== void 0 ? _a : guessOSType(value[i]);
5386
+ const type = root === exports.cameraRawFilterClassID ? 'long' : ((_a = fieldToArrayType[key]) !== null && _a !== void 0 ? _a : guessOSType(value[i]));
5004
5387
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
5005
5388
  writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
5006
- if (logErrors && !type)
5007
- console.log(`Missing descriptor array type for: '${key}' in`, value);
5389
+ if (writer.logMissingFeatures && !type)
5390
+ writer.log(`Missing descriptor array type for: '${key}' in`, value);
5008
5391
  }
5009
5392
  break;
5010
5393
  case 'doub': // Double
@@ -5304,7 +5687,7 @@ function serializeFxObject(stroke) {
5304
5687
  FrFX.overprint = !!stroke.overprint;
5305
5688
  return FrFX;
5306
5689
  }
5307
- function serializeEffects(e, log, multi) {
5690
+ function serializeEffects(e, writer, multi) {
5308
5691
  var _a, _b, _c;
5309
5692
  const info = multi ? {
5310
5693
  'Scl ': unitsPercentF((_a = e.scale) !== null && _a !== void 0 ? _a : 1),
@@ -5321,33 +5704,33 @@ function serializeEffects(e, log, multi) {
5321
5704
  const useMulti = (arr) => !!arr && arr.length > 1 && multi;
5322
5705
  const useSingle = (arr) => !!arr && arr.length >= 1 && (!multi || arr.length === 1);
5323
5706
  if (useSingle(e.dropShadow))
5324
- info.DrSh = serializeEffectObject(e.dropShadow[0], 'dropShadow', log);
5707
+ info.DrSh = serializeEffectObject(e.dropShadow[0], 'dropShadow', writer);
5325
5708
  if (useMulti(e.dropShadow))
5326
- info.dropShadowMulti = e.dropShadow.map(i => serializeEffectObject(i, 'dropShadow', log));
5709
+ info.dropShadowMulti = e.dropShadow.map(i => serializeEffectObject(i, 'dropShadow', writer));
5327
5710
  if (useSingle(e.innerShadow))
5328
- info.IrSh = serializeEffectObject(e.innerShadow[0], 'innerShadow', log);
5711
+ info.IrSh = serializeEffectObject(e.innerShadow[0], 'innerShadow', writer);
5329
5712
  if (useMulti(e.innerShadow))
5330
- info.innerShadowMulti = e.innerShadow.map(i => serializeEffectObject(i, 'innerShadow', log));
5713
+ info.innerShadowMulti = e.innerShadow.map(i => serializeEffectObject(i, 'innerShadow', writer));
5331
5714
  if (e.outerGlow)
5332
- info.OrGl = serializeEffectObject(e.outerGlow, 'outerGlow', log);
5715
+ info.OrGl = serializeEffectObject(e.outerGlow, 'outerGlow', writer);
5333
5716
  if (useMulti(e.solidFill))
5334
- info.solidFillMulti = e.solidFill.map(i => serializeEffectObject(i, 'solidFill', log));
5717
+ info.solidFillMulti = e.solidFill.map(i => serializeEffectObject(i, 'solidFill', writer));
5335
5718
  if (useMulti(e.gradientOverlay))
5336
- info.gradientFillMulti = e.gradientOverlay.map(i => serializeEffectObject(i, 'gradientOverlay', log));
5719
+ info.gradientFillMulti = e.gradientOverlay.map(i => serializeEffectObject(i, 'gradientOverlay', writer));
5337
5720
  if (useMulti(e.stroke))
5338
5721
  info.frameFXMulti = e.stroke.map(i => serializeFxObject(i));
5339
5722
  if (e.innerGlow)
5340
- info.IrGl = serializeEffectObject(e.innerGlow, 'innerGlow', log);
5723
+ info.IrGl = serializeEffectObject(e.innerGlow, 'innerGlow', writer);
5341
5724
  if (e.bevel)
5342
- info.ebbl = serializeEffectObject(e.bevel, 'bevel', log);
5725
+ info.ebbl = serializeEffectObject(e.bevel, 'bevel', writer);
5343
5726
  if (useSingle(e.solidFill))
5344
- info.SoFi = serializeEffectObject(e.solidFill[0], 'solidFill', log);
5727
+ info.SoFi = serializeEffectObject(e.solidFill[0], 'solidFill', writer);
5345
5728
  if (e.patternOverlay)
5346
- info.patternFill = serializeEffectObject(e.patternOverlay, 'patternOverlay', log);
5729
+ info.patternFill = serializeEffectObject(e.patternOverlay, 'patternOverlay', writer);
5347
5730
  if (useSingle(e.gradientOverlay))
5348
- info.GrFl = serializeEffectObject(e.gradientOverlay[0], 'gradientOverlay', log);
5731
+ info.GrFl = serializeEffectObject(e.gradientOverlay[0], 'gradientOverlay', writer);
5349
5732
  if (e.satin)
5350
- info.ChFX = serializeEffectObject(e.satin, 'satin', log);
5733
+ info.ChFX = serializeEffectObject(e.satin, 'satin', writer);
5351
5734
  if (useSingle(e.stroke))
5352
5735
  info.FrFX = serializeFxObject((_c = e.stroke) === null || _c === void 0 ? void 0 : _c[0]);
5353
5736
  if (multi) {
@@ -5369,7 +5752,7 @@ function serializeEffects(e, log, multi) {
5369
5752
  }
5370
5753
  return info;
5371
5754
  }
5372
- function parseEffects(info, log) {
5755
+ function parseEffects(info, reader) {
5373
5756
  const effects = {};
5374
5757
  const _a = info, { _name, _classID, 'Scl ': scale, masterFXSwitch, DrSh, dropShadowMulti, IrSh, innerShadowMulti, OrGl, IrGl, ebbl, SoFi, solidFillMulti, patternFill, GrFl, gradientFillMulti, ChFX, FrFX, frameFXMulti, numModifyingFX } = _a, rest = __rest(_a, ["_name", "_classID", 'Scl ', "masterFXSwitch", "DrSh", "dropShadowMulti", "IrSh", "innerShadowMulti", "OrGl", "IrGl", "ebbl", "SoFi", "solidFillMulti", "patternFill", "GrFl", "gradientFillMulti", "ChFX", "FrFX", "frameFXMulti", "numModifyingFX"]);
5375
5758
  if (!masterFXSwitch)
@@ -5377,40 +5760,40 @@ function parseEffects(info, log) {
5377
5760
  if (scale)
5378
5761
  effects.scale = parsePercent(scale);
5379
5762
  if (DrSh)
5380
- effects.dropShadow = [parseEffectObject(DrSh, log)];
5763
+ effects.dropShadow = [parseEffectObject(DrSh, reader)];
5381
5764
  if (dropShadowMulti)
5382
- effects.dropShadow = dropShadowMulti.map(i => parseEffectObject(i, log));
5765
+ effects.dropShadow = dropShadowMulti.map(i => parseEffectObject(i, reader));
5383
5766
  if (IrSh)
5384
- effects.innerShadow = [parseEffectObject(IrSh, log)];
5767
+ effects.innerShadow = [parseEffectObject(IrSh, reader)];
5385
5768
  if (innerShadowMulti)
5386
- effects.innerShadow = innerShadowMulti.map(i => parseEffectObject(i, log));
5769
+ effects.innerShadow = innerShadowMulti.map(i => parseEffectObject(i, reader));
5387
5770
  if (OrGl)
5388
- effects.outerGlow = parseEffectObject(OrGl, log);
5771
+ effects.outerGlow = parseEffectObject(OrGl, reader);
5389
5772
  if (IrGl)
5390
- effects.innerGlow = parseEffectObject(IrGl, log);
5773
+ effects.innerGlow = parseEffectObject(IrGl, reader);
5391
5774
  if (ebbl)
5392
- effects.bevel = parseEffectObject(ebbl, log, 'bevel');
5775
+ effects.bevel = parseEffectObject(ebbl, reader, 'bevel');
5393
5776
  if (SoFi)
5394
- effects.solidFill = [parseEffectObject(SoFi, log)];
5777
+ effects.solidFill = [parseEffectObject(SoFi, reader)];
5395
5778
  if (solidFillMulti)
5396
- effects.solidFill = solidFillMulti.map(i => parseEffectObject(i, log));
5779
+ effects.solidFill = solidFillMulti.map(i => parseEffectObject(i, reader));
5397
5780
  if (patternFill)
5398
- effects.patternOverlay = parseEffectObject(patternFill, log);
5781
+ effects.patternOverlay = parseEffectObject(patternFill, reader);
5399
5782
  if (GrFl)
5400
- effects.gradientOverlay = [parseEffectObject(GrFl, log)];
5783
+ effects.gradientOverlay = [parseEffectObject(GrFl, reader)];
5401
5784
  if (gradientFillMulti)
5402
- effects.gradientOverlay = gradientFillMulti.map(i => parseEffectObject(i, log));
5785
+ effects.gradientOverlay = gradientFillMulti.map(i => parseEffectObject(i, reader));
5403
5786
  if (ChFX)
5404
- effects.satin = parseEffectObject(ChFX, log);
5787
+ effects.satin = parseEffectObject(ChFX, reader);
5405
5788
  if (FrFX)
5406
5789
  effects.stroke = [parseFxObject(FrFX)];
5407
5790
  if (frameFXMulti)
5408
5791
  effects.stroke = frameFXMulti.map(i => parseFxObject(i));
5409
- if (log && Object.keys(rest).length)
5410
- console.log('Unhandled effect keys:', rest);
5792
+ if (reader.logMissingFeatures && Object.keys(rest).length)
5793
+ reader.log('Unhandled effect keys:', rest);
5411
5794
  return effects;
5412
5795
  }
5413
- function parseKeyList(keyList, logMissingFeatures) {
5796
+ function parseKeyList(keyList, reader) {
5414
5797
  const keys = [];
5415
5798
  for (let j = 0; j < keyList.length; j++) {
5416
5799
  const key = keyList[j];
@@ -5433,7 +5816,7 @@ function parseKeyList(keyList, logMissingFeatures) {
5433
5816
  case 'keyType.sheetStyle': {
5434
5817
  const key = { interpolation, time, selected, type: 'style' };
5435
5818
  if (animKey.sheetStyle.Lefx)
5436
- key.style = parseEffects(animKey.sheetStyle.Lefx, logMissingFeatures);
5819
+ key.style = parseEffects(animKey.sheetStyle.Lefx, reader);
5437
5820
  keys.push(key);
5438
5821
  break;
5439
5822
  }
@@ -5449,7 +5832,7 @@ function parseKeyList(keyList, logMissingFeatures) {
5449
5832
  }
5450
5833
  return keys;
5451
5834
  }
5452
- function serializeKeyList(keys) {
5835
+ function serializeKeyList(keys, writer) {
5453
5836
  const keyList = [];
5454
5837
  for (let j = 0; j < keys.length; j++) {
5455
5838
  const key = keys[j];
@@ -5469,7 +5852,7 @@ function serializeKeyList(keys) {
5469
5852
  case 'style':
5470
5853
  animKey = { Type: 'keyType.sheetStyle', sheetStyle: { Vrsn: 1, blendOptions: {} } };
5471
5854
  if (key.style)
5472
- animKey.sheetStyle = { Vrsn: 1, Lefx: serializeEffects(key.style, false, false), blendOptions: {} };
5855
+ animKey.sheetStyle = { Vrsn: 1, Lefx: serializeEffects(key.style, writer, false), blendOptions: {} };
5473
5856
  break;
5474
5857
  case 'globalLighting': {
5475
5858
  animKey = { Type: 'keyType.globalLighting', gblA: key.globalAngle, globalAltitude: key.globalAltitude };
@@ -5481,41 +5864,41 @@ function serializeKeyList(keys) {
5481
5864
  }
5482
5865
  return keyList;
5483
5866
  }
5484
- function parseTrackList(trackList, logMissingFeatures) {
5867
+ function parseTrackList(trackList, reader) {
5485
5868
  const tracks = [];
5486
5869
  for (let i = 0; i < trackList.length; i++) {
5487
5870
  const tr = trackList[i];
5488
5871
  const track = {
5489
5872
  type: exports.stdTrackID.decode(tr.trackID),
5490
5873
  enabled: tr.enab,
5491
- keys: parseKeyList(tr.keyList, logMissingFeatures),
5874
+ keys: parseKeyList(tr.keyList, reader),
5492
5875
  };
5493
5876
  if (tr.effectParams) {
5494
5877
  track.effectParams = {
5495
5878
  fillCanvas: tr.effectParams.fillCanvas,
5496
5879
  zoomOrigin: tr.effectParams.zoomOrigin,
5497
- keys: parseKeyList(tr.effectParams.keyList, logMissingFeatures),
5880
+ keys: parseKeyList(tr.effectParams.keyList, reader),
5498
5881
  };
5499
5882
  }
5500
5883
  tracks.push(track);
5501
5884
  }
5502
5885
  return tracks;
5503
5886
  }
5504
- function serializeTrackList(tracks) {
5887
+ function serializeTrackList(tracks, writer) {
5505
5888
  const trackList = [];
5506
5889
  for (let i = 0; i < tracks.length; i++) {
5507
5890
  const t = tracks[i];
5508
5891
  trackList.push(Object.assign(Object.assign({ trackID: exports.stdTrackID.encode(t.type), Vrsn: 1, enab: !!t.enabled, Effc: !!t.effectParams }, (t.effectParams ? {
5509
5892
  effectParams: {
5510
- keyList: serializeKeyList(t.effectParams.keys),
5893
+ keyList: serializeKeyList(t.effectParams.keys, writer),
5511
5894
  fillCanvas: t.effectParams.fillCanvas,
5512
5895
  zoomOrigin: t.effectParams.zoomOrigin,
5513
5896
  }
5514
- } : {})), { keyList: serializeKeyList(t.keys) }));
5897
+ } : {})), { keyList: serializeKeyList(t.keys, writer) }));
5515
5898
  }
5516
5899
  return trackList;
5517
5900
  }
5518
- function parseEffectObject(obj, reportErrors, objName) {
5901
+ function parseEffectObject(obj, reader, objName) {
5519
5902
  const result = {};
5520
5903
  for (const key of Object.keys(obj)) {
5521
5904
  const val = obj[key];
@@ -5668,12 +6051,12 @@ function parseEffectObject(obj, reportErrors, objName) {
5668
6051
  case '_classID':
5669
6052
  break;
5670
6053
  default:
5671
- reportErrors && console.log(`Invalid effect key: '${key}', value:`, val);
6054
+ reader.logMissingFeatures && reader.log(`Invalid effect key: '${key}', value:`, val);
5672
6055
  }
5673
6056
  }
5674
6057
  return result;
5675
6058
  }
5676
- function serializeEffectObject(obj, objName, reportErrors) {
6059
+ function serializeEffectObject(obj, objName, writer) {
5677
6060
  const result = {
5678
6061
  enab: false,
5679
6062
  };
@@ -5823,7 +6206,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
5823
6206
  result[key] = val;
5824
6207
  break;
5825
6208
  default:
5826
- reportErrors && console.log(`Invalid effect key: '${key}', value:`, val);
6209
+ writer.logMissingFeatures && writer.log(`Invalid effect key: '${key}', value:`, val);
5827
6210
  }
5828
6211
  }
5829
6212
  return result;
@@ -6068,6 +6451,21 @@ function isBookColor(color) {
6068
6451
  return color._classID === 'BkCl' || 'Bk ' in color || 'bookID' in color;
6069
6452
  }
6070
6453
  function parseColor(color) {
6454
+ var _a, _b, _c;
6455
+ const result = parseColorValues(color);
6456
+ if (isBookColor(color)) {
6457
+ const book = color;
6458
+ const key = book.bookKey;
6459
+ result.book = {
6460
+ book: (_a = book['Bk ']) !== null && _a !== void 0 ? _a : '',
6461
+ name: (_b = book['Nm ']) !== null && _b !== void 0 ? _b : '',
6462
+ bookID: (_c = book.bookID) !== null && _c !== void 0 ? _c : 0,
6463
+ bookKey: typeof key === 'string' ? key : (key ? String.fromCharCode(...Array.from(key)) : ''),
6464
+ };
6465
+ }
6466
+ return result;
6467
+ }
6468
+ function parseColorValues(color) {
6071
6469
  if ('H ' in color) {
6072
6470
  return { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
6073
6471
  }
@@ -6092,13 +6490,24 @@ function parseColor(color) {
6092
6490
  return { fr: color.redFloat, fg: color.greenFloat, fb: color.blueFloat };
6093
6491
  }
6094
6492
  else if (isBookColor(color)) {
6095
- return { r: 0, g: 0, b: 0 }; // book (Pantone) colors are not supported
6493
+ return { r: 0, g: 0, b: 0 }; // book (Pantone) color without color values
6096
6494
  }
6097
6495
  else {
6098
6496
  throw new Error('Unsupported color descriptor');
6099
6497
  }
6100
6498
  }
6101
6499
  function serializeColor(color) {
6500
+ const result = serializeColorValues(color);
6501
+ if (color === null || color === void 0 ? void 0 : color.book) {
6502
+ const { book, name, bookID, bookKey } = color.book;
6503
+ const key = new Uint8Array(bookKey.length);
6504
+ for (let i = 0; i < key.length; i++)
6505
+ key[i] = bookKey.charCodeAt(i) & 0xff;
6506
+ Object.assign(result, { 'Bk ': book, 'Nm ': name, bookID, bookKey: key });
6507
+ }
6508
+ return result;
6509
+ }
6510
+ function serializeColorValues(color) {
6102
6511
  if (!color) {
6103
6512
  return { _name: '', _classID: 'RGBC', 'Rd ': 0, 'Grn ': 0, 'Bl ': 0 };
6104
6513
  }
@@ -6524,8 +6933,13 @@ exports.presetKindType = (0, helpers_1.createEnum)('presetKindType', 'custom', {
6524
6933
  custom: 'presetKindCustom',
6525
6934
  default: 'presetKindDefault',
6526
6935
  });
6936
+ exports.patternColorHandling = (0, helpers_1.createEnum)('', 'convert', {
6937
+ 'convert': 'conv',
6938
+ 'avoid conversion': 'avod',
6939
+ 'luminance only': 'lumi',
6940
+ });
6527
6941
 
6528
- },{"./helpers":8,"./psdReader":13,"./psdWriter":14}],5:[function(require,module,exports){
6942
+ },{"./helpers":9,"./psdReader":14,"./psdWriter":15}],6:[function(require,module,exports){
6529
6943
  "use strict";
6530
6944
  Object.defineProperty(exports, "__esModule", { value: true });
6531
6945
  exports.readEffects = readEffects;
@@ -6813,7 +7227,7 @@ function writeEffects(writer, effects) {
6813
7227
  }
6814
7228
  }
6815
7229
 
6816
- },{"./helpers":8,"./psdReader":13,"./psdWriter":14}],6:[function(require,module,exports){
7230
+ },{"./helpers":9,"./psdReader":14,"./psdWriter":15}],7:[function(require,module,exports){
6817
7231
  "use strict";
6818
7232
  Object.defineProperty(exports, "__esModule", { value: true });
6819
7233
  exports.setProperty = setProperty;
@@ -7174,7 +7588,7 @@ function serializeEngineData(data, condensed = false) {
7174
7588
  return buffer.slice(0, offset);
7175
7589
  }
7176
7590
 
7177
- },{}],7:[function(require,module,exports){
7591
+ },{}],8:[function(require,module,exports){
7178
7592
  "use strict";
7179
7593
  /// Engine data 2 experiments
7180
7594
  // /test/engineData2.json:1109 is character codes
@@ -7614,7 +8028,7 @@ function decodeEngineData2(data) {
7614
8028
  return result;
7615
8029
  }
7616
8030
 
7617
- },{"./engineData":6}],8:[function(require,module,exports){
8031
+ },{"./engineData":7}],9:[function(require,module,exports){
7618
8032
  "use strict";
7619
8033
  Object.defineProperty(exports, "__esModule", { value: true });
7620
8034
  exports.createImageData = exports.createCanvas = exports.MaskParams = exports.LayerMaskFlags = exports.ColorSpace = exports.largeAdditionalInfoKeys = exports.largeAdditionalInfoKeysObserved = exports.layerColors = exports.toBlendMode = exports.fromBlendMode = exports.MOCK_HANDLERS = void 0;
@@ -7625,11 +8039,16 @@ exports.normalizeLabAB = normalizeLabAB;
7625
8039
  exports.denormalizeLabAB = denormalizeLabAB;
7626
8040
  exports.clamp = clamp;
7627
8041
  exports.hasAlpha = hasAlpha;
8042
+ exports.cmykToRgbValues = cmykToRgbValues;
8043
+ exports.rgbToCmykValues = rgbToCmykValues;
7628
8044
  exports.resetImageData = resetImageData;
7629
8045
  exports.imageDataToCanvas = imageDataToCanvas;
7630
8046
  exports.decodeBitmap = decodeBitmap;
7631
8047
  exports.writeDataRaw = writeDataRaw;
7632
8048
  exports.writeDataRLE = writeDataRLE;
8049
+ exports.planarToBytes = planarToBytes;
8050
+ exports.writeDataRLEBytes = writeDataRLEBytes;
8051
+ exports.writeDataZipWithPrediction = writeDataZipWithPrediction;
7633
8052
  exports.writeDataZipWithoutPrediction = writeDataZipWithoutPrediction;
7634
8053
  exports.createCanvasFromData = createCanvasFromData;
7635
8054
  exports.initializeCanvas = initializeCanvas;
@@ -7669,7 +8088,7 @@ exports.toBlendMode = {
7669
8088
  };
7670
8089
  Object.keys(exports.toBlendMode).forEach(key => exports.fromBlendMode[exports.toBlendMode[key]] = key);
7671
8090
  exports.layerColors = [
7672
- 'none', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'gray'
8091
+ 'none', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'gray', 'seafoam', 'indigo', 'magenta', 'fuchsia',
7673
8092
  ];
7674
8093
  // keys not listed in documentation that Photoshop writes with 64bit length in PSB files (with 8B64 signature)
7675
8094
  exports.largeAdditionalInfoKeysObserved = ['lnk3', 'lnkE', 'pths', 'extd', 'extn', 'FELS', 'artd'];
@@ -7756,13 +8175,152 @@ function clamp(value, min, max) {
7756
8175
  }
7757
8176
  function hasAlpha(data) {
7758
8177
  const size = data.width * data.height * 4;
8178
+ const max = data.data instanceof Float32Array ? 1 : (data.data instanceof Uint16Array ? 0xffff : 0xff);
7759
8179
  for (let i = 3; i < size; i += 4) {
7760
- if (data.data[i] !== 255) {
8180
+ if (data.data[i] !== max) {
7761
8181
  return true;
7762
8182
  }
7763
8183
  }
7764
8184
  return false;
7765
8185
  }
8186
+ // Polynomial approximation of U.S. Web Coated (SWOP) v2 CMYK to RGB conversion (default CMYK profile of Photoshop).
8187
+ // Coefficients are taken from pdf.js (DeviceCmykCS in src/core/colorspace.js, https://github.com/mozilla/pdf.js),
8188
+ // Copyright 2012 Mozilla Foundation, licensed under the Apache License, Version 2.0
8189
+ // (http://www.apache.org/licenses/LICENSE-2.0)
8190
+ // c, m, y, k - ink values (0 - 1), output - RGB values (0 - 255, not rounded or clamped)
8191
+ function cmykToRgbValues(c, m, y, k, out) {
8192
+ out[0] = 255 +
8193
+ c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) +
8194
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) +
8195
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) +
8196
+ k * (-21.86122147463605 * k - 189.48180835922747);
8197
+ out[1] = 255 +
8198
+ c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) +
8199
+ m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) +
8200
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
8201
+ k * (-20.737325471181034 * k - 187.80453709719578);
8202
+ out[2] = 255 +
8203
+ c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) +
8204
+ m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) +
8205
+ y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) +
8206
+ k * (-22.33816807309886 * k - 180.12613974708367);
8207
+ }
8208
+ const clamp01 = (v) => v < 0 ? 0 : (v > 1 ? 1 : v);
8209
+ // finds c, m, y (with fixed k) for given RGB color using Gauss-Newton method, returns squared error
8210
+ function solveCmy(r, g, b, k, x) {
8211
+ const f = [0, 0, 0], f2 = [0, 0, 0], e = [0, 0, 0];
8212
+ const J = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
8213
+ const h = 1e-4;
8214
+ for (let iteration = 0; iteration < 20; iteration++) {
8215
+ cmykToRgbValues(x[0], x[1], x[2], k, f);
8216
+ e[0] = f[0] - r;
8217
+ e[1] = f[1] - g;
8218
+ e[2] = f[2] - b;
8219
+ if ((e[0] * e[0] + e[1] * e[1] + e[2] * e[2]) < 1e-6)
8220
+ break;
8221
+ for (let j = 0; j < 3; j++) {
8222
+ const s = x[j];
8223
+ x[j] = s + h;
8224
+ cmykToRgbValues(x[0], x[1], x[2], k, f2);
8225
+ x[j] = s;
8226
+ for (let i = 0; i < 3; i++)
8227
+ J[i][j] = (f2[i] - f[i]) / h;
8228
+ }
8229
+ const [[a, b_, c], [d, e_, f_], [g_, h_, i_]] = J;
8230
+ const det = a * (e_ * i_ - f_ * h_) - b_ * (d * i_ - f_ * g_) + c * (d * h_ - e_ * g_);
8231
+ if (Math.abs(det) < 1e-12)
8232
+ break;
8233
+ const inverse = [
8234
+ [(e_ * i_ - f_ * h_), (c * h_ - b_ * i_), (b_ * f_ - c * e_)],
8235
+ [(f_ * g_ - d * i_), (a * i_ - c * g_), (c * d - a * f_)],
8236
+ [(d * h_ - e_ * g_), (b_ * g_ - a * h_), (a * e_ - b_ * d)],
8237
+ ];
8238
+ let changed = 0;
8239
+ for (let j = 0; j < 3; j++) {
8240
+ const delta = -(inverse[j][0] * e[0] + inverse[j][1] * e[1] + inverse[j][2] * e[2]) / det;
8241
+ const value = clamp01(x[j] + delta);
8242
+ changed += Math.abs(value - x[j]);
8243
+ x[j] = value;
8244
+ }
8245
+ if (changed < 1e-9)
8246
+ break;
8247
+ }
8248
+ cmykToRgbValues(x[0], x[1], x[2], k, f);
8249
+ return (f[0] - r) * (f[0] - r) + (f[1] - g) * (f[1] - g) + (f[2] - b) * (f[2] - b);
8250
+ }
8251
+ // finds CMYK ink values (0 - 1) for RGB color (0 - 255), out of gamut colors are approximated
8252
+ function rgbToCmykExact(r, g, b, out) {
8253
+ const max = Math.max(r, g, b) / 255;
8254
+ const blackGeneration = Math.pow(clamp01((1 - max - 0.2) / 0.8), 1.3);
8255
+ const x = [0, 0, 0];
8256
+ let bestScore = Infinity, bestError = Infinity;
8257
+ const tryBlack = (k) => {
8258
+ x[0] = clamp01(1 - r / 255 - k);
8259
+ x[1] = clamp01(1 - g / 255 - k);
8260
+ x[2] = clamp01(1 - b / 255 - k);
8261
+ const error = solveCmy(r, g, b, k, x);
8262
+ // prefer solutions close to black generation value if the error is small enough
8263
+ const score = Math.max(error, 0.1) + Math.abs(k - blackGeneration) * 0.01;
8264
+ if (score < bestScore) {
8265
+ bestScore = score;
8266
+ bestError = error;
8267
+ out[0] = x[0];
8268
+ out[1] = x[1];
8269
+ out[2] = x[2];
8270
+ out[3] = k;
8271
+ }
8272
+ };
8273
+ tryBlack(blackGeneration);
8274
+ if (bestError > 0.1) {
8275
+ for (let i = 0; i <= 10; i++)
8276
+ tryBlack(i / 10);
8277
+ }
8278
+ if (bestError > 0.1) {
8279
+ const k = out[3];
8280
+ for (let i = -5; i <= 5; i++)
8281
+ tryBlack(clamp01(k + i / 100));
8282
+ }
8283
+ }
8284
+ const cmykLutSize = 33;
8285
+ let cmykLut;
8286
+ function getCmykLut() {
8287
+ if (!cmykLut) {
8288
+ const n = cmykLutSize;
8289
+ const lut = new Float32Array(n * n * n * 4);
8290
+ const out = [0, 0, 0, 0];
8291
+ for (let r = 0, o = 0; r < n; r++) {
8292
+ for (let g = 0; g < n; g++) {
8293
+ for (let b = 0; b < n; b++, o += 4) {
8294
+ rgbToCmykExact(r * 255 / (n - 1), g * 255 / (n - 1), b * 255 / (n - 1), out);
8295
+ lut[o] = out[0];
8296
+ lut[o + 1] = out[1];
8297
+ lut[o + 2] = out[2];
8298
+ lut[o + 3] = out[3];
8299
+ }
8300
+ }
8301
+ }
8302
+ cmykLut = lut;
8303
+ }
8304
+ return cmykLut;
8305
+ }
8306
+ // inverse of cmykToRgbValues, r, g, b - RGB values (0 - 1), output - CMYK ink values (0 - 1)
8307
+ function rgbToCmykValues(r, g, b, out) {
8308
+ const lut = getCmykLut();
8309
+ const n1 = cmykLutSize - 1;
8310
+ const fr = clamp01(r) * n1, fg = clamp01(g) * n1, fb = clamp01(b) * n1;
8311
+ const r0 = Math.min(n1 - 1, Math.floor(fr)), g0 = Math.min(n1 - 1, Math.floor(fg)), b0 = Math.min(n1 - 1, Math.floor(fb));
8312
+ const dr = fr - r0, dg = fg - g0, db = fb - b0;
8313
+ out[0] = out[1] = out[2] = out[3] = 0;
8314
+ for (let i = 0; i < 8; i++) {
8315
+ const ir = i >> 2, ig = (i >> 1) & 1, ib = i & 1;
8316
+ const w = (ir ? dr : 1 - dr) * (ig ? dg : 1 - dg) * (ib ? db : 1 - db);
8317
+ const o = (((r0 + ir) * cmykLutSize + g0 + ig) * cmykLutSize + b0 + ib) * 4;
8318
+ out[0] += w * lut[o];
8319
+ out[1] += w * lut[o + 1];
8320
+ out[2] += w * lut[o + 2];
8321
+ out[3] += w * lut[o + 3];
8322
+ }
8323
+ }
7766
8324
  function resetImageData({ data }) {
7767
8325
  const alpha = (data instanceof Float32Array) ? 1.0 : ((data instanceof Uint16Array) ? 0xffff : 0xff);
7768
8326
  for (let p = 0, size = data.length | 0; p < size; p = (p + 4) | 0) {
@@ -7921,6 +8479,102 @@ function writeDataRLE(buffer, { data, width, height }, offsets, large) {
7921
8479
  // returns view of the buffer, copy the data if the buffer is going to be reused
7922
8480
  return buffer.subarray(0, o);
7923
8481
  }
8482
+ // converts channel values to big-endian bytes
8483
+ function planarToBytes(values) {
8484
+ if (values instanceof Uint8Array)
8485
+ return values;
8486
+ const bytes = new Uint8Array(values.byteLength);
8487
+ const view = new DataView(bytes.buffer);
8488
+ if (values instanceof Uint16Array) {
8489
+ for (let i = 0; i < values.length; i++)
8490
+ view.setUint16(i * 2, values[i], false);
8491
+ }
8492
+ else {
8493
+ for (let i = 0; i < values.length; i++)
8494
+ view.setFloat32(i * 4, values[i], false);
8495
+ }
8496
+ return bytes;
8497
+ }
8498
+ // RLE (PackBits) compression of rows of bytes, prefixed with byte counts of each row
8499
+ function writeDataRLEBytes(bytes, rowBytes, height, large) {
8500
+ const countSize = large ? 4 : 2;
8501
+ const buffer = new Uint8Array(height * (countSize + rowBytes + Math.ceil(rowBytes / 128)));
8502
+ let o = countSize * height;
8503
+ for (let y = 0; y < height; y++) {
8504
+ const start = o;
8505
+ const rowStart = y * rowBytes;
8506
+ const rowEnd = rowStart + rowBytes;
8507
+ let i = rowStart;
8508
+ while (i < rowEnd) {
8509
+ let run = 1;
8510
+ while (i + run < rowEnd && run < 128 && bytes[i + run] === bytes[i])
8511
+ run++;
8512
+ if (run > 1) {
8513
+ buffer[o++] = 257 - run;
8514
+ buffer[o++] = bytes[i];
8515
+ i += run;
8516
+ }
8517
+ else {
8518
+ // literal bytes until a run of at least 3 equal bytes
8519
+ const countIndex = o++;
8520
+ let count = 0;
8521
+ while (i < rowEnd && count < 128) {
8522
+ if (i + 2 < rowEnd && bytes[i] === bytes[i + 1] && bytes[i] === bytes[i + 2])
8523
+ break;
8524
+ buffer[o++] = bytes[i++];
8525
+ count++;
8526
+ }
8527
+ buffer[countIndex] = count - 1;
8528
+ }
8529
+ }
8530
+ const length = o - start;
8531
+ for (let j = 0; j < countSize; j++) {
8532
+ buffer[y * countSize + j] = (length >>> ((countSize - j - 1) * 8)) & 0xff;
8533
+ }
8534
+ }
8535
+ return buffer.subarray(0, o);
8536
+ }
8537
+ // zip compression with prediction (values are delta encoded per row, 32bit values are split into byte planes first)
8538
+ function writeDataZipWithPrediction(values, width, height) {
8539
+ let bytes;
8540
+ if (values instanceof Uint8Array) {
8541
+ bytes = new Uint8Array(width * height);
8542
+ for (let y = 0, i = 0; y < height; y++) {
8543
+ for (let x = 0, prev = 0; x < width; x++, i++) {
8544
+ bytes[i] = values[i] - prev; // Uint8Array wraps values on assignment
8545
+ prev = values[i];
8546
+ }
8547
+ }
8548
+ }
8549
+ else if (values instanceof Uint16Array) {
8550
+ bytes = new Uint8Array(width * height * 2);
8551
+ for (let y = 0, i = 0; y < height; y++) {
8552
+ for (let x = 0, prev = 0; x < width; x++, i++) {
8553
+ const delta = (values[i] - prev) & 0xffff;
8554
+ bytes[i * 2] = delta >> 8;
8555
+ bytes[i * 2 + 1] = delta & 0xff;
8556
+ prev = values[i];
8557
+ }
8558
+ }
8559
+ }
8560
+ else {
8561
+ const rowBytes = width * 4;
8562
+ const source = planarToBytes(values);
8563
+ bytes = new Uint8Array(rowBytes * height);
8564
+ for (let y = 0; y < height; y++) {
8565
+ const row = y * rowBytes;
8566
+ for (let x = 0; x < width; x++) {
8567
+ for (let b = 0; b < 4; b++) {
8568
+ bytes[row + b * width + x] = source[row + x * 4 + b];
8569
+ }
8570
+ }
8571
+ for (let x = rowBytes - 1; x > 0; x--) {
8572
+ bytes[row + x] -= bytes[row + x - 1];
8573
+ }
8574
+ }
8575
+ }
8576
+ return (0, pako_1.deflate)(bytes);
8577
+ }
7924
8578
  function writeDataZipWithoutPrediction({ data, width, height }, offsets) {
7925
8579
  const size = width * height;
7926
8580
  const channel = new Uint8Array(size);
@@ -7985,7 +8639,7 @@ function initializeCanvas(createCanvasMethod, createImageDataMethod) {
7985
8639
  exports.createImageData = createImageDataMethod || exports.createImageData;
7986
8640
  }
7987
8641
 
7988
- },{"./jpeg":11,"pako":20}],9:[function(require,module,exports){
8642
+ },{"./jpeg":12,"pako":21}],10:[function(require,module,exports){
7989
8643
  "use strict";
7990
8644
  Object.defineProperty(exports, "__esModule", { value: true });
7991
8645
  exports.resourceHandlersMap = exports.resourceHandlers = void 0;
@@ -8501,6 +9155,38 @@ function writeTransferFunctions(writer, functions) {
8501
9155
  (0, psdWriter_1.writeUint16)(writer, f.override ? 1 : 0);
8502
9156
  }
8503
9157
  }
9158
+ addHandler(1014, // Duotone halftoning information
9159
+ // Duotone halftoning information
9160
+ target => target.duotoneHalftoneScreens !== undefined, (reader, target, left) => target.duotoneHalftoneScreens = readHalftoneScreens(reader, left), (writer, target) => writeHalftoneScreens(writer, target.duotoneHalftoneScreens));
9161
+ addHandler(1017, // Duotone transfer functions
9162
+ // Duotone transfer functions
9163
+ target => target.duotoneTransferFunctions !== undefined, (reader, target, left) => target.duotoneTransferFunctions = readTransferFunctions(reader, left), (writer, target) => writeTransferFunctions(writer, target.duotoneTransferFunctions));
9164
+ addHandler(1018, // Duotone image information
9165
+ // Duotone image information
9166
+ target => target.duotoneImageInformation !== undefined, (reader, target, left) => target.duotoneImageInformation = (0, psdReader_1.readBytes)(reader, left()), (writer, target) => (0, psdWriter_1.writeBytes)(writer, target.duotoneImageInformation));
9167
+ addHandler(1066, // Alternate duotone colors
9168
+ // Alternate duotone colors
9169
+ target => target.alternateDuotoneColors !== undefined, (reader, target, left) => {
9170
+ if ((0, psdReader_1.readUint16)(reader) !== 1)
9171
+ throw new Error('Invalid alternate duotone colors version');
9172
+ const colors = [];
9173
+ const count = (0, psdReader_1.readUint16)(reader);
9174
+ for (let i = 0; i < count && left() >= 10; i++)
9175
+ colors.push((0, psdReader_1.readColor)(reader));
9176
+ const labCount = (0, psdReader_1.readUint16)(reader);
9177
+ if (labCount * 3 > left())
9178
+ throw new Error('Invalid alternate duotone colors Lab table size');
9179
+ const labColors = (0, psdReader_1.readBytes)(reader, labCount * 3);
9180
+ target.alternateDuotoneColors = { colors, labColors };
9181
+ }, (writer, target) => {
9182
+ const { colors, labColors } = target.alternateDuotoneColors;
9183
+ (0, psdWriter_1.writeUint16)(writer, 1); // version
9184
+ (0, psdWriter_1.writeUint16)(writer, colors.length);
9185
+ for (const color of colors)
9186
+ (0, psdWriter_1.writeColor)(writer, color);
9187
+ (0, psdWriter_1.writeUint16)(writer, Math.floor(labColors.byteLength / 3));
9188
+ (0, psdWriter_1.writeBytes)(writer, labColors.subarray(0, Math.floor(labColors.byteLength / 3) * 3));
9189
+ });
8504
9190
  addHandler(1015, // Grayscale and multichannel transfer function
8505
9191
  // Grayscale and multichannel transfer function
8506
9192
  target => target.grayscaleTransferFunctions !== undefined, (reader, target, left) => target.grayscaleTransferFunctions = readTransferFunctions(reader, left), (writer, target) => writeTransferFunctions(writer, target.grayscaleTransferFunctions));
@@ -8766,7 +9452,7 @@ target => target.timelineInformation !== undefined, (reader, target) => {
8766
9452
  workOutTime: (0, descriptor_1.frac)(desc.workOutTime),
8767
9453
  repeats: desc.LCnt,
8768
9454
  hasMotion: desc.hasMotion,
8769
- globalTracks: (0, descriptor_1.parseTrackList)(desc.globalTrackList, !!reader.logMissingFeatures),
9455
+ globalTracks: (0, descriptor_1.parseTrackList)(desc.globalTrackList, reader),
8770
9456
  };
8771
9457
  if ((_b = (_a = desc.audioClipGroupList) === null || _a === void 0 ? void 0 : _a.audioClipGroupList) === null || _b === void 0 ? void 0 : _b.length) {
8772
9458
  target.timelineInformation.audioClipGroups = desc.audioClipGroupList.audioClipGroupList.map(g => ({
@@ -8805,7 +9491,7 @@ target => target.timelineInformation !== undefined, (reader, target) => {
8805
9491
  workInTime: timeline.workInTime,
8806
9492
  workOutTime: timeline.workOutTime,
8807
9493
  LCnt: timeline.repeats,
8808
- globalTrackList: (0, descriptor_1.serializeTrackList)(timeline.globalTracks),
9494
+ globalTrackList: (0, descriptor_1.serializeTrackList)(timeline.globalTracks, writer),
8809
9495
  audioClipGroupList: {
8810
9496
  audioClipGroupList: ((_a = timeline.audioClipGroups) !== null && _a !== void 0 ? _a : []).map(a => ({
8811
9497
  groupID: a.id,
@@ -9063,10 +9749,13 @@ target => target.iccProfile !== undefined, (reader, target, left) => {
9063
9749
  addHandler(1044, target => target.idsSeedNumber !== undefined, (reader, target) => target.idsSeedNumber = (0, psdReader_1.readUint32)(reader), (writer, target) => (0, psdWriter_1.writeUint32)(writer, target.idsSeedNumber));
9064
9750
  addHandler(1038, // Color samplers (Photoshop 5.0, replaced by 1073 in CS3)
9065
9751
  // Color samplers (Photoshop 5.0, replaced by 1073 in CS3)
9066
- target => target.colorSamplers !== undefined, (reader, target, left) => {
9752
+ target => target.colorSamplers !== undefined && !target.colorSamplers.some(s => s.depth !== undefined), (reader, target, left) => {
9753
+ var _a;
9067
9754
  const version = (0, psdReader_1.readUint32)(reader);
9068
9755
  if (version !== 1)
9069
9756
  throw new Error(`Invalid color samplers version: ${version}`);
9757
+ if ((_a = target.colorSamplers) === null || _a === void 0 ? void 0 : _a.some(s => s.depth !== undefined))
9758
+ return (0, psdReader_1.skipBytes)(reader, left()); // already read from 1073
9070
9759
  const count = (0, psdReader_1.readUint32)(reader);
9071
9760
  target.colorSamplers = [];
9072
9761
  for (let i = 0; i < count && left() >= 10; i++) {
@@ -9086,6 +9775,52 @@ target => target.colorSamplers !== undefined, (reader, target, left) => {
9086
9775
  (0, psdWriter_1.writeInt16)(writer, sampler.colorSpace);
9087
9776
  }
9088
9777
  });
9778
+ addHandler(1073, // Color samplers (Photoshop CS3)
9779
+ // Color samplers (Photoshop CS3)
9780
+ target => target.colorSamplers !== undefined && target.colorSamplers.some(s => s.depth !== undefined), (reader, target, left) => {
9781
+ const version = (0, psdReader_1.readUint32)(reader);
9782
+ if (version < 1 || version > 3)
9783
+ throw new Error(`Invalid color samplers version: ${version}`);
9784
+ const count = (0, psdReader_1.readUint32)(reader);
9785
+ target.colorSamplers = [];
9786
+ for (let i = 0; i < count && left() >= 10; i++) {
9787
+ // position is fixed point value for sampler version 1 (stored the same way as in 1038 resource) or float for version 2
9788
+ const samplerVersion = version === 3 ? (0, psdReader_1.readUint32)(reader) : version;
9789
+ const y = samplerVersion === 1 ? (0, psdReader_1.readInt32)(reader) / 16 : (0, psdReader_1.readFloat32)(reader);
9790
+ const x = samplerVersion === 1 ? (0, psdReader_1.readInt32)(reader) / 16 : (0, psdReader_1.readFloat32)(reader);
9791
+ const colorSpace = (0, psdReader_1.readInt16)(reader);
9792
+ const depth = version >= 2 ? (0, psdReader_1.readInt16)(reader) : 1;
9793
+ target.colorSamplers.push({ x, y, colorSpace, depth });
9794
+ }
9795
+ }, (writer, target) => {
9796
+ var _a;
9797
+ (0, psdWriter_1.writeUint32)(writer, 3); // version
9798
+ (0, psdWriter_1.writeUint32)(writer, target.colorSamplers.length);
9799
+ for (const sampler of target.colorSamplers) {
9800
+ (0, psdWriter_1.writeUint32)(writer, 1); // sampler version
9801
+ (0, psdWriter_1.writeInt32)(writer, Math.round(sampler.y * 16));
9802
+ (0, psdWriter_1.writeInt32)(writer, Math.round(sampler.x * 16));
9803
+ (0, psdWriter_1.writeInt16)(writer, sampler.colorSpace);
9804
+ (0, psdWriter_1.writeInt16)(writer, (_a = sampler.depth) !== null && _a !== void 0 ? _a : 1);
9805
+ }
9806
+ });
9807
+ addHandler(1022, // Quick Mask information
9808
+ // Quick Mask information
9809
+ target => target.quickMaskInfo !== undefined, (reader, target) => {
9810
+ const channelId = (0, psdReader_1.readUint16)(reader);
9811
+ const initiallyEmpty = !!(0, psdReader_1.readUint8)(reader);
9812
+ target.quickMaskInfo = { channelId, initiallyEmpty };
9813
+ }, (writer, target) => {
9814
+ (0, psdWriter_1.writeUint16)(writer, target.quickMaskInfo.channelId);
9815
+ (0, psdWriter_1.writeUint8)(writer, target.quickMaskInfo.initiallyEmpty ? 1 : 0);
9816
+ });
9817
+ addHandler(1074, // Measurement scale
9818
+ // Measurement scale
9819
+ target => target.measurementScale !== undefined, (reader, target, left) => {
9820
+ target.measurementScale = (0, psdReader_1.readBytes)(reader, left());
9821
+ }, (writer, target) => {
9822
+ (0, psdWriter_1.writeBytes)(writer, target.measurementScale);
9823
+ });
9089
9824
  addHandler(1042, // Effects visible (only present when effects are hidden)
9090
9825
  // Effects visible (only present when effects are hidden)
9091
9826
  target => target.effectsVisible !== undefined, (reader, target) => {
@@ -9419,7 +10154,7 @@ target => pluginResourceKeys(target).length, (reader, target, left) => {
9419
10154
  }
9420
10155
  }, { keyCount: 1000 });
9421
10156
 
9422
- },{"./additionalInfo":2,"./descriptor":4,"./helpers":8,"./psdReader":13,"./psdWriter":14,"./utf8":16,"base64-js":17}],10:[function(require,module,exports){
10157
+ },{"./additionalInfo":2,"./descriptor":5,"./helpers":9,"./psdReader":14,"./psdWriter":15,"./utf8":17,"base64-js":18}],11:[function(require,module,exports){
9423
10158
  (function (Buffer){(function (){
9424
10159
  "use strict";
9425
10160
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
@@ -9456,6 +10191,7 @@ Object.defineProperty(exports, "getCompositeCanvas", { enumerable: true, get: fu
9456
10191
  const base64_js_1 = require("base64-js");
9457
10192
  __exportStar(require("./abr"), exports);
9458
10193
  __exportStar(require("./csh"), exports);
10194
+ __exportStar(require("./ase"), exports);
9459
10195
  var helpers_1 = require("./helpers");
9460
10196
  Object.defineProperty(exports, "initializeCanvas", { enumerable: true, get: function () { return helpers_1.initializeCanvas; } });
9461
10197
  __exportStar(require("./psd"), exports);
@@ -9485,7 +10221,7 @@ function writePsdBuffer(psd, options) {
9485
10221
  }
9486
10222
 
9487
10223
  }).call(this)}).call(this,require("buffer").Buffer)
9488
- },{"./abr":1,"./csh":3,"./helpers":8,"./psd":12,"./psdReader":13,"./psdWriter":14,"base64-js":17,"buffer":18}],11:[function(require,module,exports){
10224
+ },{"./abr":1,"./ase":3,"./csh":4,"./helpers":9,"./psd":13,"./psdReader":14,"./psdWriter":15,"base64-js":18,"buffer":19}],12:[function(require,module,exports){
9489
10225
  "use strict";
9490
10226
  // based on https://github.com/jpeg-js/jpeg-js
9491
10227
  /*
@@ -10539,7 +11275,7 @@ function decodeJpeg(encoded, createImageData) {
10539
11275
  return imageData;
10540
11276
  }
10541
11277
 
10542
- },{}],12:[function(require,module,exports){
11278
+ },{}],13:[function(require,module,exports){
10543
11279
  "use strict";
10544
11280
  Object.defineProperty(exports, "__esModule", { value: true });
10545
11281
  exports.Compression = exports.ChannelID = exports.LayerCompCapturedInfo = exports.SectionDividerType = exports.ColorMode = void 0;
@@ -10588,7 +11324,7 @@ var Compression;
10588
11324
  Compression[Compression["ZipWithPrediction"] = 3] = "ZipWithPrediction";
10589
11325
  })(Compression || (exports.Compression = Compression = {}));
10590
11326
 
10591
- },{}],13:[function(require,module,exports){
11327
+ },{}],14:[function(require,module,exports){
10592
11328
  "use strict";
10593
11329
  var __rest = (this && this.__rest) || function (s, e) {
10594
11330
  var t = {};
@@ -10797,6 +11533,8 @@ function readUnicodeString(reader) {
10797
11533
  return readUnicodeStringWithLength(reader, length);
10798
11534
  }
10799
11535
  const STRING_CHUNK_SIZE = 0x2000;
11536
+ // shorter strings (most descriptor keys, OSTypes and names) are faster to build with simple loop than String.fromCharCode.apply
11537
+ const SHORT_STRING_LENGTH = 64;
10800
11538
  function checkReadBounds(reader, size) {
10801
11539
  if (reader.offset < 0 || (reader.offset + size) > reader.view.byteLength) {
10802
11540
  throw new RangeError('Offset is outside the bounds of the DataView');
@@ -10807,9 +11545,18 @@ function readUtf16String(reader, length, littleEndian) {
10807
11545
  return '';
10808
11546
  checkReadBounds(reader, length * 2);
10809
11547
  const view = reader.view;
10810
- const codes = new Uint16Array(Math.min(length, STRING_CHUNK_SIZE));
10811
11548
  let offset = reader.offset;
10812
11549
  let text = '';
11550
+ if (length <= SHORT_STRING_LENGTH) {
11551
+ for (let i = 0; i < length; i++, offset += 2) {
11552
+ text += String.fromCharCode(view.getUint16(offset, littleEndian));
11553
+ }
11554
+ reader.offset = offset;
11555
+ if (text.charCodeAt(text.length - 1) === 0)
11556
+ text = text.substring(0, text.length - 1);
11557
+ return text;
11558
+ }
11559
+ const codes = new Uint16Array(Math.min(length, STRING_CHUNK_SIZE));
10813
11560
  for (let i = 0; i < length; i += STRING_CHUNK_SIZE) {
10814
11561
  const count = Math.min(STRING_CHUNK_SIZE, length - i);
10815
11562
  for (let j = 0; j < count; j++, offset += 2) {
@@ -10840,6 +11587,15 @@ function readAsciiString(reader, length) {
10840
11587
  if (!(length > 0))
10841
11588
  return '';
10842
11589
  checkReadBounds(reader, length);
11590
+ if (length <= SHORT_STRING_LENGTH) {
11591
+ const view = reader.view;
11592
+ let text = '';
11593
+ for (let i = 0, offset = reader.offset; i < length; i++, offset++) {
11594
+ text += String.fromCharCode(view.getUint8(offset));
11595
+ }
11596
+ reader.offset += length;
11597
+ return text;
11598
+ }
10843
11599
  const text = bytesToString(new Uint8Array(reader.view.buffer, reader.view.byteOffset + reader.offset, length));
10844
11600
  reader.offset += length;
10845
11601
  return text;
@@ -10855,7 +11611,14 @@ function checkSignature(reader, a, b) {
10855
11611
  }
10856
11612
  }
10857
11613
  function readShortString(reader, length) {
10858
- return bytesToString(readBytes(reader, length));
11614
+ const bytes = readBytes(reader, length);
11615
+ if (length > SHORT_STRING_LENGTH)
11616
+ return bytesToString(bytes);
11617
+ let text = '';
11618
+ for (let i = 0; i < bytes.length; i++) {
11619
+ text += String.fromCharCode(bytes[i]);
11620
+ }
11621
+ return text;
10859
11622
  }
10860
11623
  function isValidSignature(sig) {
10861
11624
  return sig === '8BIM' || sig === 'MeSa' || sig === 'AgHg' || sig === 'PHUT' || sig === 'DCSR';
@@ -11041,6 +11804,9 @@ function readLayerInfo(reader, psd, imageResources) {
11041
11804
  if (type === 1 /* SectionDividerType.OpenFolder */ || type === 2 /* SectionDividerType.ClosedFolder */) {
11042
11805
  l.opened = type === 1 /* SectionDividerType.OpenFolder */;
11043
11806
  l.children = [];
11807
+ // group layers can't have image data, some broken files have it, ignore it like Photoshop does
11808
+ delete l.canvas;
11809
+ delete l.imageData;
11044
11810
  if ((_a = l.sectionDivider) === null || _a === void 0 ? void 0 : _a.key) {
11045
11811
  l.blendMode = (_b = helpers_1.toBlendMode[l.sectionDivider.key]) !== null && _b !== void 0 ? _b : l.blendMode;
11046
11812
  }
@@ -11239,9 +12005,8 @@ function readLayerChannelImageData(reader, psd, layer, channels) {
11239
12005
  const start = reader.offset;
11240
12006
  let compression = 0 /* Compression.RawData */;
11241
12007
  let data = undefined;
11242
- if (channel.length === 1)
11243
- throw new Error('Invalid channel length');
11244
- if (channel.length) {
12008
+ // channel length of 1 is invalid (should be 0 or at least 2), skip the byte and treat channel as empty
12009
+ if (channel.length >= 2) {
11245
12010
  compression = readUint16(reader);
11246
12011
  // try to fix broken files where there's 1 byte shift of channel
11247
12012
  if (compression > 3) {
@@ -11263,7 +12028,16 @@ function readLayerChannelImageData(reader, psd, layer, channels) {
11263
12028
  layer.rawData.channels.push({ id: channel.id, compression, data });
11264
12029
  }
11265
12030
  if (!reader.useRawData) {
11266
- decodeLayerImageData(layer, reader);
12031
+ try {
12032
+ decodeLayerImageData(layer, reader);
12033
+ }
12034
+ catch (e) {
12035
+ // corrupted image data of one layer shouldn't prevent reading rest of the file
12036
+ if (reader.throwForMissingFeatures || e.message === 'Exceeded memory limit')
12037
+ throw e;
12038
+ reader.logMissingFeatures && reader.log(`Failed to decode layer image data: ${e.message}`);
12039
+ delete layer.rawData;
12040
+ }
11267
12041
  }
11268
12042
  }
11269
12043
  function resetAlpha({ data }, cmyk) {
@@ -11467,7 +12241,7 @@ function readGlobalLayerMaskInfo(reader) {
11467
12241
  const colorSpace2 = readUint16(reader);
11468
12242
  const colorSpace3 = readUint16(reader);
11469
12243
  const colorSpace4 = readUint16(reader);
11470
- const opacity = readUint16(reader) / 100; // 0 - 100
12244
+ const opacity = Math.min(readUint16(reader), 100) / 100; // 0 - 100 (some files have values out of range)
11471
12245
  const kind = readUint8(reader);
11472
12246
  skipBytes(reader, left()); // 3 bytes of padding ?
11473
12247
  return { overlayColorSpace, colorSpace1, colorSpace2, colorSpace3, colorSpace4, opacity, kind };
@@ -11717,10 +12491,7 @@ function toRange(value, max) {
11717
12491
  value = Math.round(value * (max / 255));
11718
12492
  return value <= 0 ? 0 : (value >= max ? max : value);
11719
12493
  }
11720
- // Polynomial approximation of U.S. Web Coated (SWOP) v2 CMYK to RGB conversion (default CMYK profile of Photoshop).
11721
- // Coefficients are taken from pdf.js (DeviceCmykCS in src/core/colorspace.js, https://github.com/mozilla/pdf.js),
11722
- // Copyright 2012 Mozilla Foundation, licensed under the Apache License, Version 2.0
11723
- // (http://www.apache.org/licenses/LICENSE-2.0)
12494
+ // converts CMYK data to RGB using approximation of U.S. Web Coated (SWOP) v2 profile (see cmykToRgbValues)
11724
12495
  // cmyk - 8 or 16 bit data with 5 channels (cmyka), rgb - 8 or 16 bit data with 4 channels (rgba)
11725
12496
  // removeMatte - colors are blended with white (no ink), used for composite image of documents with global alpha
11726
12497
  function cmykToRgb(cmyk, rgb, removeMatte) {
@@ -11729,6 +12500,7 @@ function cmykToRgb(cmyk, rgb, removeMatte) {
11729
12500
  const dstData = rgb.data;
11730
12501
  const srcMax = srcData instanceof Uint16Array ? 0xffff : 0xff;
11731
12502
  const dstMax = dstData instanceof Uint16Array ? 0xffff : 0xff;
12503
+ const out = [0, 0, 0];
11732
12504
  for (let src = 0, dst = 0; dst < size; src += 5, dst += 4) {
11733
12505
  const a = srcData[src + 4];
11734
12506
  // image data stores inverted values (0 = 100% ink)
@@ -11743,21 +12515,10 @@ function cmykToRgb(cmyk, rgb, removeMatte) {
11743
12515
  y = Math.min(1, y * ra);
11744
12516
  k = Math.min(1, k * ra);
11745
12517
  }
11746
- dstData[dst] = toRange(255 +
11747
- c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) +
11748
- m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) +
11749
- y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) +
11750
- k * (-21.86122147463605 * k - 189.48180835922747), dstMax);
11751
- dstData[dst + 1] = toRange(255 +
11752
- c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) +
11753
- m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) +
11754
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
11755
- k * (-20.737325471181034 * k - 187.80453709719578), dstMax);
11756
- dstData[dst + 2] = toRange(255 +
11757
- c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) +
11758
- m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) +
11759
- y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) +
11760
- k * (-22.33816807309886 * k - 180.12613974708367), dstMax);
12518
+ (0, helpers_1.cmykToRgbValues)(c, m, y, k, out);
12519
+ dstData[dst] = toRange(out[0], dstMax);
12520
+ dstData[dst + 1] = toRange(out[1], dstMax);
12521
+ dstData[dst + 2] = toRange(out[2], dstMax);
11761
12522
  dstData[dst + 3] = srcMax === dstMax ? a : Math.round(a * dstMax / srcMax);
11762
12523
  }
11763
12524
  }
@@ -11924,8 +12685,8 @@ function readDataZip(compressed, pixelData, width, height, bitDepth, step, offse
11924
12685
  recoverMemory(reader, expectedSize);
11925
12686
  }
11926
12687
  }
11927
- // decodes single PackBits row, returns number of decoded values
11928
- function decodeRLERow(src, i, end, dst, p, step, count) {
12688
+ // decodes single PackBits row into byte buffer, returns number of decoded bytes
12689
+ function decodeRLERow(src, i, end, dst, count) {
11929
12690
  let x = 0;
11930
12691
  while (i < end && x < count) {
11931
12692
  const header = src[i++];
@@ -11936,10 +12697,8 @@ function decodeRLERow(src, i, end, dst, p, step, count) {
11936
12697
  let n = 257 - header;
11937
12698
  if (n > count - x)
11938
12699
  n = count - x;
12700
+ dst.fill(value, x, x + n);
11939
12701
  x += n;
11940
- for (; n > 0; n--, p += step) {
11941
- dst[p] = value;
11942
- }
11943
12702
  }
11944
12703
  else if (header < 128) {
11945
12704
  let n = header + 1;
@@ -11947,9 +12706,8 @@ function decodeRLERow(src, i, end, dst, p, step, count) {
11947
12706
  n = count - x;
11948
12707
  if (n > end - i)
11949
12708
  n = end - i;
11950
- x += n;
11951
- for (; n > 0; n--, p += step) {
11952
- dst[p] = src[i++];
12709
+ for (; n > 0; n--) {
12710
+ dst[x++] = src[i++];
11953
12711
  }
11954
12712
  }
11955
12713
  else {
@@ -11958,6 +12716,47 @@ function decodeRLERow(src, i, end, dst, p, step, count) {
11958
12716
  }
11959
12717
  return x;
11960
12718
  }
12719
+ // decodes RLE rows of single 8bit channel, writing values to `data` with `step`
12720
+ // (kept as single function with the loops, inlining row decoder into readDataRLE makes V8 generate much slower code)
12721
+ function decodeRLEChannel8(src, lengths, li, pos, width, height, data, offset, step) {
12722
+ const srcEnd = src.length | 0;
12723
+ for (let y = 0; y < height; y++, li++) {
12724
+ let i = (pos < srcEnd ? pos : srcEnd) | 0;
12725
+ pos += lengths[li];
12726
+ const end = (pos < srcEnd ? pos : srcEnd) | 0;
12727
+ let p = (offset + y * width * step) | 0;
12728
+ let x = 0;
12729
+ while (i < end && x < width) {
12730
+ const header = src[i++] | 0;
12731
+ if (header > 128) {
12732
+ if (i >= end)
12733
+ break;
12734
+ const value = src[i++] | 0;
12735
+ let n = (257 - header) | 0;
12736
+ if (n > width - x)
12737
+ n = (width - x) | 0;
12738
+ x = (x + n) | 0;
12739
+ for (const pe = (p + n * step) | 0; p < pe; p = (p + step) | 0) {
12740
+ data[p] = value;
12741
+ }
12742
+ }
12743
+ else if (header < 128) {
12744
+ let n = (header + 1) | 0;
12745
+ if (n > width - x)
12746
+ n = (width - x) | 0;
12747
+ if (n > end - i)
12748
+ n = (end - i) | 0;
12749
+ x = (x + n) | 0;
12750
+ for (const ie = (i + n) | 0; i < ie; i = (i + 1) | 0, p = (p + step) | 0) {
12751
+ data[p] = src[i];
12752
+ }
12753
+ }
12754
+ else {
12755
+ // ignore 128
12756
+ }
12757
+ }
12758
+ }
12759
+ }
11961
12760
  // converts big-endian 16/32-bit values from bytes and writes them to `data` starting at `p` with `step`
11962
12761
  function scatterValues(bytes, count, bpv, data, p, step) {
11963
12762
  if (bpv === 2) {
@@ -11972,8 +12771,8 @@ function scatterValues(bytes, count, bpv, data, p, step) {
11972
12771
  }
11973
12772
  }
11974
12773
  }
11975
- // decodes RLE rows of single channel, each row starts at the beginning of the image row
11976
- function decodeRLEChannel(src, lengths, li, pos, width, height, data, offset, step, bpv, row) {
12774
+ // decodes RLE rows of single 16bit or 32bit channel, each row is decoded into `row` buffer and then converted to values
12775
+ function decodeRLEChannelWide(src, lengths, li, pos, width, height, data, offset, step, bpv, row) {
11977
12776
  const srcEnd = src.length;
11978
12777
  const rowSize = width * bpv;
11979
12778
  for (let y = 0; y < height; y++, li++) {
@@ -11982,25 +12781,24 @@ function decodeRLEChannel(src, lengths, li, pos, width, height, data, offset, st
11982
12781
  const rowEnd = pos < srcEnd ? pos : srcEnd;
11983
12782
  if (rowStart >= rowEnd)
11984
12783
  continue;
11985
- if (bpv === 1) {
11986
- decodeRLERow(src, rowStart, rowEnd, data, offset + y * width * step, step, width);
11987
- }
11988
- else {
11989
- const decoded = decodeRLERow(src, rowStart, rowEnd, row, 0, 1, rowSize);
11990
- scatterValues(row, Math.floor(decoded / bpv), bpv, data, offset + y * width * step, step);
11991
- }
12784
+ const decoded = decodeRLERow(src, rowStart, rowEnd, row, rowSize);
12785
+ scatterValues(row, Math.floor(decoded / bpv), bpv, data, offset + y * width * step, step);
11992
12786
  }
11993
12787
  }
11994
12788
  function readDataRLE(reader, pixelData, width, height, bitDepth, step, offsets, large) {
11995
12789
  const data = pixelData && pixelData.data;
11996
12790
  const rows = offsets.length * height;
11997
12791
  const lengthSize = large ? 4 : 2;
11998
- consumeMemory(reader, rows * lengthSize);
12792
+ const lengthsMemory = rows * lengthSize;
12793
+ const srcEnd = reader.view.byteLength;
12794
+ const bpv = bytesPerValue(bitDepth); // throws before consuming memory
12795
+ let lengths;
12796
+ consumeMemory(reader, lengthsMemory);
11999
12797
  try {
12000
- if ((reader.offset + rows * lengthSize) > reader.view.byteLength) {
12798
+ if ((reader.offset + lengthsMemory) > srcEnd) {
12001
12799
  throw new Error('RLE row lengths exceed buffer length');
12002
12800
  }
12003
- const lengths = large ? new Uint32Array(rows) : new Uint16Array(rows);
12801
+ lengths = large ? new Uint32Array(rows) : new Uint16Array(rows);
12004
12802
  let total = 0;
12005
12803
  if (large) {
12006
12804
  for (let i = 0; i < rows; i++)
@@ -12010,32 +12808,37 @@ function readDataRLE(reader, pixelData, width, height, bitDepth, step, offsets,
12010
12808
  for (let i = 0; i < rows; i++)
12011
12809
  total += (lengths[i] = readUint16(reader));
12012
12810
  }
12013
- const start = reader.offset;
12014
- const srcEnd = reader.view.byteLength;
12015
- if (total > (srcEnd - start)) {
12811
+ if (total > (srcEnd - reader.offset)) {
12016
12812
  // broken or truncated file, decode only data that is available
12017
12813
  warnOrThrow(reader, 'RLE data exceeds buffer length');
12018
12814
  }
12019
- const bpv = bytesPerValue(bitDepth);
12020
12815
  if (data)
12021
12816
  verifyArrayType(data, bpv);
12022
- const src = new Uint8Array(reader.view.buffer, reader.view.byteOffset, srcEnd);
12023
- const row = (data && bpv > 1) ? new Uint8Array(width * bpv) : undefined;
12024
- let pos = start;
12025
- for (let c = 0, li = 0; c < offsets.length; c++, li += height) {
12026
- const offset = offsets[c] | 0;
12027
- const channelStart = pos;
12028
- for (let y = 0; y < height; y++)
12029
- pos += lengths[li + y];
12030
- if (data && offset >= 0 && offset < step) {
12031
- decodeRLEChannel(src, lengths, li, channelStart, width, height, data, offset, step, bpv, row);
12817
+ }
12818
+ catch (e) {
12819
+ recoverMemory(reader, lengthsMemory);
12820
+ throw e;
12821
+ }
12822
+ // decoding can't throw, it's kept outside of try block because V8 generates much slower code for loops inlined into try block
12823
+ const src = new Uint8Array(reader.view.buffer, reader.view.byteOffset, srcEnd);
12824
+ const row = (data && bpv > 1) ? new Uint8Array(width * bpv) : undefined;
12825
+ let pos = reader.offset;
12826
+ for (let c = 0, li = 0; c < offsets.length; c++, li += height) {
12827
+ const offset = offsets[c] | 0;
12828
+ const channelStart = pos;
12829
+ for (let y = 0; y < height; y++)
12830
+ pos += lengths[li + y];
12831
+ if (data && offset >= 0 && offset < step) {
12832
+ if (bpv === 1) {
12833
+ decodeRLEChannel8(src, lengths, li, channelStart, width, height, data, offset, step);
12834
+ }
12835
+ else {
12836
+ decodeRLEChannelWide(src, lengths, li, channelStart, width, height, data, offset, step, bpv, row);
12032
12837
  }
12033
12838
  }
12034
- reader.offset = pos;
12035
- }
12036
- finally {
12037
- recoverMemory(reader, rows * lengthSize);
12038
12839
  }
12840
+ reader.offset = pos;
12841
+ recoverMemory(reader, lengthsMemory);
12039
12842
  }
12040
12843
  function readSection(reader, round, func, skipEmpty = true, eightBytes = false) {
12041
12844
  let length = readUint32(reader);
@@ -12177,19 +12980,13 @@ function readPattern(reader) {
12177
12980
  // channels cover whole pattern, each 2 bytes of RLE data can produce at most 128 bytes
12178
12981
  if (width * height > (Math.min(end, reader.view.byteLength) - reader.offset) * 64)
12179
12982
  throw new Error('Pattern data out of bounds');
12180
- const size = width * height * 4;
12181
- consumeMemory(reader, size);
12182
- const data = new Uint8Array(size);
12183
- for (let i = 3; i < data.byteLength; i += 4) {
12184
- data[i] = 255;
12185
- }
12186
12983
  // first written arrays are color channels, next one is transparency (Photoshop stores it in the last, sheet mask, array)
12187
12984
  const colorChannels = colorMode === 3 /* ColorMode.RGB */ ? 3 : (colorMode === 4 /* ColorMode.CMYK */ ? 4 : 1);
12188
- // CMYK channels are decoded into separate buffer (5 values per pixel, inverted, 0 = 100% ink) and converted to RGB at the end
12189
- const cmyk = colorMode === 4 /* ColorMode.CMYK */ ? new Uint8Array(width * height * 5).fill(255) : undefined;
12190
- if (cmyk)
12191
- consumeMemory(reader, cmyk.byteLength);
12192
- const alphaTarget = cmyk ? 4 : 3;
12985
+ const isCmyk = colorMode === 4 /* ColorMode.CMYK */;
12986
+ const alphaTarget = isCmyk ? 4 : 3;
12987
+ const channels = [];
12988
+ let maxDecodeSize = 0;
12989
+ // validate all channels before allocating any image data
12193
12990
  for (let i = 0, ch = 0; i < (channelsCount + 2) && reader.offset + 4 <= end; i++) {
12194
12991
  const has = readUint32(reader);
12195
12992
  if (!has)
@@ -12221,72 +13018,107 @@ function readPattern(reader) {
12221
13018
  const h = cbottom - ctop;
12222
13019
  const rowBytes = w * (depth / 8);
12223
13020
  const channelSize = rowBytes * h;
12224
- let bytes;
12225
13021
  if (compressionMode === 0) {
12226
13022
  if (cdata.byteLength < channelSize)
12227
13023
  throw new Error('Pattern channel data out of bounds');
12228
- bytes = cdata;
12229
13024
  }
12230
13025
  else if (compressionMode === 1) {
12231
13026
  // each 2 bytes of RLE data can produce at most 128 bytes
12232
13027
  if (channelSize > cdata.byteLength * 64)
12233
13028
  throw new Error('Pattern channel data out of bounds');
12234
- consumeMemory(reader, channelSize);
12235
- bytes = new Uint8Array(channelSize);
12236
- const cdataReader = createReader(cdata.buffer, cdata.byteOffset, cdata.byteLength);
12237
- readDataRLE(cdataReader, { data: bytes, width: rowBytes, height: h }, rowBytes, h, 8, 1, [0], false);
13029
+ maxDecodeSize = Math.max(maxDecodeSize, channelSize);
12238
13030
  }
12239
13031
  else {
12240
13032
  throw new Error('Invalid pattern compression mode');
12241
13033
  }
13034
+ channels.push({ target, depth, compressionMode, cdata, ctop, cleft, w, h, rowBytes, channelSize });
13035
+ }
13036
+ // check peak memory up front (image data, CMYK buffer and largest RLE decode buffer),
13037
+ // image data is consumed only after successful decoding so failed patterns don't reduce the limit
13038
+ const size = width * height * 4;
13039
+ const cmykSize = isCmyk ? width * height * 5 : 0;
13040
+ consumeMemory(reader, size + cmykSize + maxDecodeSize);
13041
+ recoverMemory(reader, size + cmykSize + maxDecodeSize);
13042
+ const data = new Uint8Array(size);
13043
+ for (let i = 3; i < data.byteLength; i += 4) {
13044
+ data[i] = 255;
13045
+ }
13046
+ // CMYK channels are decoded into separate buffer (5 values per pixel, inverted, 0 = 100% ink) and converted to RGB at the end
13047
+ const cmyk = isCmyk ? new Uint8Array(cmykSize).fill(255) : undefined;
13048
+ for (const { target, depth, compressionMode, cdata, ctop, cleft, w, h, rowBytes, channelSize } of channels) {
13049
+ let bytes = cdata;
13050
+ if (compressionMode === 1) {
13051
+ bytes = new Uint8Array(channelSize);
13052
+ const cdataReader = createReader(cdata.buffer, cdata.byteOffset, cdata.byteLength);
13053
+ readDataRLE(cdataReader, { data: bytes, width: rowBytes, height: h }, rowBytes, h, 8, 1, [0], false);
13054
+ }
13055
+ if (depth !== 8)
13056
+ bytes = patternChannelTo8bit(bytes, w * h, depth);
12242
13057
  const ox = cleft - left;
12243
13058
  const oy = ctop - top;
12244
- for (let y = 0; y < h; y++) {
12245
- for (let x = 0; x < w; x++) {
12246
- const src = x + y * w;
12247
- const dst = (ox + x + (y + oy) * width) * 4;
12248
- const value = depth === 8 ? bytes[src] : patternValueTo8bit(bytes, src, depth);
12249
- if (cmyk) {
12250
- cmyk[(ox + x + (y + oy) * width) * 5 + target] = value;
12251
- }
12252
- else if (target === 3) {
12253
- data[dst + 3] = value;
12254
- }
12255
- else if (colorMode === 2 /* ColorMode.Indexed */) {
12256
- const color = palette[value];
12257
- data[dst + 0] = color.r;
12258
- data[dst + 1] = color.g;
12259
- data[dst + 2] = color.b;
13059
+ if (cmyk) {
13060
+ copyPatternChannel(bytes, cmyk, w, h, (ox + oy * width) * 5 + target, width * 5, 5);
13061
+ }
13062
+ else if (target === 3 || colorMode === 3 /* ColorMode.RGB */) {
13063
+ copyPatternChannel(bytes, data, w, h, (ox + oy * width) * 4 + target, width * 4, 4);
13064
+ }
13065
+ else if (colorMode === 2 /* ColorMode.Indexed */) {
13066
+ const colors = new Uint8Array(256 * 3);
13067
+ for (let i = 0; i < 256; i++) {
13068
+ colors[i * 3 + 0] = palette[i].r;
13069
+ colors[i * 3 + 1] = palette[i].g;
13070
+ colors[i * 3 + 2] = palette[i].b;
13071
+ }
13072
+ for (let y = 0; y < h; y++) {
13073
+ for (let x = 0, src = y * w, dst = (ox + (y + oy) * width) * 4; x < w; x++, src++, dst += 4) {
13074
+ const index = bytes[src] * 3;
13075
+ data[dst + 0] = colors[index + 0];
13076
+ data[dst + 1] = colors[index + 1];
13077
+ data[dst + 2] = colors[index + 2];
12260
13078
  }
12261
- else if (colorMode === 1 /* ColorMode.Grayscale */) {
13079
+ }
13080
+ }
13081
+ else { // grayscale
13082
+ for (let y = 0; y < h; y++) {
13083
+ for (let x = 0, src = y * w, dst = (ox + (y + oy) * width) * 4; x < w; x++, src++, dst += 4) {
13084
+ const value = bytes[src];
12262
13085
  data[dst + 0] = value;
12263
13086
  data[dst + 1] = value;
12264
13087
  data[dst + 2] = value;
12265
13088
  }
12266
- else {
12267
- data[dst + target] = value;
12268
- }
12269
13089
  }
12270
13090
  }
12271
- if (compressionMode === 1)
12272
- recoverMemory(reader, channelSize);
12273
13091
  }
12274
13092
  if (cmyk) {
12275
13093
  cmykToRgb({ width, height, data: cmyk }, { width, height, data }, false);
12276
- recoverMemory(reader, cmyk.byteLength);
12277
13094
  }
13095
+ consumeMemory(reader, size);
12278
13096
  reader.offset = end;
12279
13097
  return { id, name, x, y, bounds: { x: left, y: top, w: width, h: height }, data };
12280
13098
  }
12281
- // converts big-endian 16bit or 32bit (float) value at given index to 8bit value
12282
- function patternValueTo8bit(bytes, index, depth) {
13099
+ // converts big-endian 16bit or 32bit (float) values to 8bit values
13100
+ function patternChannelTo8bit(bytes, count, depth) {
13101
+ const result = new Uint8Array(count);
12283
13102
  if (depth === 16) {
12284
- return Math.round(((bytes[index * 2] << 8) | bytes[index * 2 + 1]) / 257);
13103
+ for (let i = 0; i < count; i++) {
13104
+ result[i] = Math.round(((bytes[i * 2] << 8) | bytes[i * 2 + 1]) / 257);
13105
+ }
12285
13106
  }
12286
13107
  else {
12287
- const view = new DataView(bytes.buffer, bytes.byteOffset + index * 4, 4);
12288
- const value = view.getFloat32(0, false);
12289
- return value > 0 ? (value < 1 ? Math.round(value * 255) : 255) : 0;
13108
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
13109
+ for (let i = 0; i < count; i++) {
13110
+ const value = view.getFloat32(i * 4, false);
13111
+ result[i] = value > 0 ? (value < 1 ? Math.round(value * 255) : 255) : 0;
13112
+ }
13113
+ }
13114
+ return result;
13115
+ }
13116
+ // copies w x h channel values into interleaved data starting at `offset`
13117
+ function copyPatternChannel(bytes, data, w, h, offset, stride, step) {
13118
+ for (let y = 0, src = 0; y < h; y++) {
13119
+ for (let x = 0, dst = offset + y * stride; x < w; x++, src++, dst += step) {
13120
+ data[dst] = bytes[src];
13121
+ }
12290
13122
  }
12291
13123
  }
12292
13124
  function consumeMemory(reader, size) {
@@ -12304,7 +13136,7 @@ function recoverMemory(reader, size) {
12304
13136
  }
12305
13137
  }
12306
13138
 
12307
- },{"./additionalInfo":2,"./helpers":8,"./imageResources":9,"./utf8":16,"pako":20}],14:[function(require,module,exports){
13139
+ },{"./additionalInfo":2,"./helpers":9,"./imageResources":10,"./utf8":17,"pako":21}],15:[function(require,module,exports){
12308
13140
  "use strict";
12309
13141
  Object.defineProperty(exports, "__esModule", { value: true });
12310
13142
  exports.createWriter = createWriter;
@@ -12337,6 +13169,7 @@ exports.writePsd = writePsd;
12337
13169
  exports.writeColor = writeColor;
12338
13170
  exports.writePattern = writePattern;
12339
13171
  const helpers_1 = require("./helpers");
13172
+ const pako_1 = require("pako");
12340
13173
  const additionalInfo_1 = require("./additionalInfo");
12341
13174
  const imageResources_1 = require("./imageResources");
12342
13175
  const psdReader_1 = require("./psdReader");
@@ -12509,10 +13342,33 @@ function writeSection(writer, round, func, writeTotalLength = false, large = fal
12509
13342
  function verifyPixelData(data, name) {
12510
13343
  // check element size instead of instanceof, so arrays from other realms (iframes, workers, vm) are accepted
12511
13344
  const bytesPerElement = data && data.data.BYTES_PER_ELEMENT;
12512
- if (bytesPerElement !== undefined && bytesPerElement !== 1) {
12513
- throw new Error(`${name} has incorrect bitDepth (only 8-bit Uint8Array or Uint8ClampedArray data is supported for writing)`);
13345
+ if (bytesPerElement !== undefined && bytesPerElement !== 1 && bytesPerElement !== 2 && !(data.data instanceof Float32Array)) {
13346
+ throw new Error(`${name} has incorrect bitDepth (only Uint8Array, Uint8ClampedArray, Uint16Array and Float32Array data is supported for writing)`);
12514
13347
  }
12515
13348
  }
13349
+ // supported bit depths for each color mode
13350
+ const writeBitDepths = {
13351
+ [0 /* ColorMode.Bitmap */]: [1],
13352
+ [1 /* ColorMode.Grayscale */]: [8, 16, 32],
13353
+ [2 /* ColorMode.Indexed */]: [8],
13354
+ [3 /* ColorMode.RGB */]: [8, 16, 32],
13355
+ [4 /* ColorMode.CMYK */]: [8, 16],
13356
+ };
13357
+ const colorModeNames = {
13358
+ [0 /* ColorMode.Bitmap */]: 'Bitmap', [1 /* ColorMode.Grayscale */]: 'Grayscale', [2 /* ColorMode.Indexed */]: 'Indexed', [3 /* ColorMode.RGB */]: 'RGB',
13359
+ [4 /* ColorMode.CMYK */]: 'CMYK', [7 /* ColorMode.Multichannel */]: 'Multichannel', [8 /* ColorMode.Duotone */]: 'Duotone', [9 /* ColorMode.Lab */]: 'Lab',
13360
+ };
13361
+ function colorChannelsCount(colorMode) {
13362
+ return colorMode === 3 /* ColorMode.RGB */ ? 3 : (colorMode === 4 /* ColorMode.CMYK */ ? 4 : 1);
13363
+ }
13364
+ // HDR toning settings that Photoshop stores in color mode data of 32bit documents (default values of new document),
13365
+ // Photoshop refuses to open 32bit documents without them
13366
+ const hdrToningData = [
13367
+ 104, 100, 114, 116, 0, 0, 0, 3, 62, 107, 133, 31, 0, 0, 0, 2, 0, 0, 0, 7, 0, 76, 0, 105, 0, 110, 0, 101, 0, 97, 0, 114, 0, 0,
13368
+ 0, 2, 0, 2, 0, 0, 0, 0, 0, 255, 0, 255, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 65, 128, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 63, 128, 0, 0,
13369
+ 104, 100, 114, 97, 0, 0, 0, 6, 0, 0, 0, 0, 65, 160, 0, 0, 65, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 0, 0, 0, 0,
13370
+ 0, 0,
13371
+ ];
12516
13372
  function verifyBitCount(target) {
12517
13373
  var _a, _b, _c;
12518
13374
  (_a = target.children) === null || _a === void 0 ? void 0 : _a.forEach(verifyBitCount);
@@ -12523,34 +13379,37 @@ function verifyBitCount(target) {
12523
13379
  verifyPixelData((_c = target.realMask) === null || _c === void 0 ? void 0 : _c.imageData, 'realMask imageData');
12524
13380
  }
12525
13381
  function writePsd(writer, psd, options = {}) {
12526
- var _a;
13382
+ var _a, _b, _c, _d;
12527
13383
  if (!(+psd.width > 0 && +psd.height > 0))
12528
13384
  throw new Error('Invalid document size');
12529
13385
  if ((psd.width > 30000 || psd.height > 30000) && !options.psb)
12530
13386
  throw new Error('Document size is too large (max is 30000x30000, use PSB format instead)');
12531
- const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
12532
- if (bitsPerChannel !== 8)
12533
- throw new Error('bitsPerChannel other than 8 are not supported for writing');
13387
+ const colorMode = (_a = psd.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
13388
+ const bitsPerChannel = (_b = psd.bitsPerChannel) !== null && _b !== void 0 ? _b : (colorMode === 0 /* ColorMode.Bitmap */ ? 1 : 8);
13389
+ const bitDepths = writeBitDepths[colorMode];
13390
+ if (!bitDepths)
13391
+ throw new Error(`${(_c = colorModeNames[colorMode]) !== null && _c !== void 0 ? _c : colorMode} color mode is not supported for writing`);
13392
+ if (bitDepths.indexOf(bitsPerChannel) === -1)
13393
+ throw new Error(`bitsPerChannel ${bitsPerChannel} is not supported for writing in ${colorModeNames[colorMode]} color mode`);
13394
+ // Photoshop doesn't support layers in bitmap and indexed color modes
13395
+ const layersAllowed = colorMode !== 0 /* ColorMode.Bitmap */ && colorMode !== 2 /* ColorMode.Indexed */;
13396
+ if (!layersAllowed && ((_d = psd.children) === null || _d === void 0 ? void 0 : _d.length))
13397
+ throw new Error(`Layers are not supported in ${colorModeNames[colorMode]} color mode`);
13398
+ if (colorMode === 2 /* ColorMode.Indexed */ && !psd.palette)
13399
+ throw new Error('Missing color palette for Indexed color mode');
12534
13400
  if (options.log)
12535
13401
  writer.log = options.log;
13402
+ if (options.logMissingFeatures)
13403
+ writer.logMissingFeatures = true;
12536
13404
  const layers = [];
12537
13405
  addChildren(layers, psd.children);
12538
- if (!layers.length)
13406
+ if (!layers.length && layersAllowed)
12539
13407
  layers.push({});
12540
13408
  verifyBitCount(psd);
12541
13409
  const imageResources = Object.assign({}, psd.imageResources);
12542
- const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map() });
12543
- // document is always written in RGB color mode, skip resources specific to original color mode
12544
- if (psd.colorMode !== undefined && psd.colorMode !== 3 /* ColorMode.RGB */) {
12545
- delete imageResources.iccProfile;
12546
- delete imageResources.indexedColorCount;
12547
- delete imageResources.transparencyIndex;
12548
- delete imageResources.alphaChannelDisplayInfo;
12549
- delete imageResources.colorHalftoneScreens;
12550
- delete imageResources.grayscaleHalftoneScreens;
12551
- delete imageResources.colorTransferFunctions;
12552
- delete imageResources.grayscaleTransferFunctions;
12553
- }
13410
+ const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map(), colorMode, bitsPerChannel });
13411
+ // 16 and 32 bit documents store layers in Lr16 / Lr32 section of global additional info
13412
+ const layersInGlobalInfo = bitsPerChannel === 16 || bitsPerChannel === 32;
12554
13413
  if (opt.generateThumbnail) {
12555
13414
  imageResources.thumbnail = createThumbnail(psd);
12556
13415
  }
@@ -12563,20 +13422,34 @@ function writePsd(writer, psd, options = {}) {
12563
13422
  }
12564
13423
  if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
12565
13424
  throw new Error('Document canvas must have the same size as document');
12566
- const globalAlpha = !!imageData && (0, helpers_1.hasAlpha)(imageData);
13425
+ const globalAlpha = !!imageData && layersAllowed && (0, helpers_1.hasAlpha)(imageData);
12567
13426
  // only used for encoding a single layer channel at a time, composite image is encoded directly into the writer buffer
12568
13427
  writer.tempBuffer = new Uint8Array(getLargestLayerSize(psd.children, !!options.psb));
12569
13428
  // header
12570
13429
  writeSignature(writer, '8BPS');
12571
13430
  writeUint16(writer, options.psb ? 2 : 1); // version
12572
13431
  writeZeros(writer, 6);
12573
- writeUint16(writer, globalAlpha ? 4 : 3); // channels
13432
+ writeUint16(writer, colorChannelsCount(colorMode) + (globalAlpha ? 1 : 0)); // channels
12574
13433
  writeUint32(writer, psd.height);
12575
13434
  writeUint32(writer, psd.width);
12576
13435
  writeUint16(writer, bitsPerChannel); // bits per channel
12577
- writeUint16(writer, 3 /* ColorMode.RGB */); // we only support saving RGB right now
12578
- // color mode data (empty for RGB color mode)
12579
- writeUint32(writer, 0);
13436
+ writeUint16(writer, colorMode);
13437
+ // color mode data
13438
+ writeSection(writer, 1, () => {
13439
+ var _a, _b, _c, _d, _e, _f;
13440
+ if (colorMode === 2 /* ColorMode.Indexed */) {
13441
+ const palette = psd.palette;
13442
+ for (let i = 0; i < 256; i++)
13443
+ writeUint8(writer, (_b = (_a = palette[i]) === null || _a === void 0 ? void 0 : _a.r) !== null && _b !== void 0 ? _b : 0);
13444
+ for (let i = 0; i < 256; i++)
13445
+ writeUint8(writer, (_d = (_c = palette[i]) === null || _c === void 0 ? void 0 : _c.g) !== null && _d !== void 0 ? _d : 0);
13446
+ for (let i = 0; i < 256; i++)
13447
+ writeUint8(writer, (_f = (_e = palette[i]) === null || _e === void 0 ? void 0 : _e.b) !== null && _f !== void 0 ? _f : 0);
13448
+ }
13449
+ else if (bitsPerChannel === 32) {
13450
+ writeBytes(writer, new Uint8Array(hdrToningData));
13451
+ }
13452
+ });
12580
13453
  // image resources
12581
13454
  imageResources.layersGroup = layers.map(l => l.linkGroup || 0);
12582
13455
  imageResources.layerGroupsEnabledId = layers.map(l => l.linkGroupEnabled == false ? 0 : 1);
@@ -12596,20 +13469,202 @@ function writePsd(writer, psd, options = {}) {
12596
13469
  });
12597
13470
  // layer and mask info
12598
13471
  writeSection(writer, 2, () => {
12599
- writeLayerInfo(writer, layers, psd, globalAlpha, opt);
13472
+ if (layersInGlobalInfo || !layersAllowed) {
13473
+ writeSection(writer, 4, () => { }, true, opt.psb); // empty layer info
13474
+ }
13475
+ else {
13476
+ writeLayerInfo(writer, layers, psd, globalAlpha, opt);
13477
+ }
12600
13478
  writeGlobalLayerMaskInfo(writer, psd.globalLayerMaskInfo);
13479
+ if (layersInGlobalInfo) {
13480
+ if (globalAlpha)
13481
+ writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Mt16' : 'Mt32', !!opt.psb, () => { });
13482
+ writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Lr16' : 'Lr32', !!opt.psb, () => {
13483
+ writeLayerInfoData(writer, layers, psd, globalAlpha, opt);
13484
+ });
13485
+ }
12601
13486
  writeAdditionalLayerInfo(writer, psd, psd, opt);
12602
13487
  }, undefined, !!opt.psb);
12603
13488
  writer.tempBuffer = undefined;
12604
13489
  // image data
12605
- writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
12606
- const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
12607
- const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
12608
- // encode directly into the writer buffer
12609
- const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
12610
- ensureSize(writer, writer.offset + maxSize);
12611
- const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
12612
- writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
13490
+ if (colorMode === 3 /* ColorMode.RGB */ && bitsPerChannel === 8 && (!imageData || is8bit(imageData))) {
13491
+ writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
13492
+ const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
13493
+ const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
13494
+ // encode directly into the writer buffer
13495
+ const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
13496
+ ensureSize(writer, writer.offset + maxSize);
13497
+ const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
13498
+ writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
13499
+ }
13500
+ else {
13501
+ writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, !!options.psb);
13502
+ }
13503
+ }
13504
+ function writeGlobalInfoSection(writer, key, psb, func) {
13505
+ writeSignature(writer, psb ? '8B64' : '8BIM');
13506
+ writeSignature(writer, key);
13507
+ writeSection(writer, 4, func, false, psb);
13508
+ }
13509
+ function is8bit(data) {
13510
+ return data.data.BYTES_PER_ELEMENT === 1;
13511
+ }
13512
+ // converts image data (8, 16 or 32 bit RGBA data) to channels of the document color mode and bit depth
13513
+ function getPlanarChannels(imageData, colorMode, bitsPerChannel, matte) {
13514
+ const { data, width, height } = imageData;
13515
+ const size = width * height;
13516
+ const srcFloat = data instanceof Float32Array;
13517
+ const srcMax = srcFloat ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
13518
+ const dstFloat = bitsPerChannel === 32;
13519
+ const dstMax = dstFloat ? 1 : (bitsPerChannel === 16 ? 0xffff : 0xff);
13520
+ const colorCount = colorChannelsCount(colorMode);
13521
+ const create = () => dstFloat ? new Float32Array(size) : (bitsPerChannel === 16 ? new Uint16Array(size) : new Uint8Array(size));
13522
+ const colors = [];
13523
+ for (let i = 0; i < colorCount; i++)
13524
+ colors.push(create());
13525
+ const alpha = create();
13526
+ // color values are gamma corrected when converting between float (linear) and integer values (same as imageDataToCanvas)
13527
+ const toNormalized = (v) => srcFloat ? Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) : v / srcMax;
13528
+ const fromNormalized = (v) => dstFloat ? Math.pow(v, 2.2) : Math.round((0, helpers_1.clamp)(v, 0, 1) * dstMax);
13529
+ const sameType = srcFloat === dstFloat && srcMax === dstMax;
13530
+ const convertColor = (v) => sameType ? (dstFloat ? v : Math.round(v)) : fromNormalized(toNormalized(v));
13531
+ const convertAlpha = (v) => sameType ? v : (dstFloat ? v / srcMax : Math.round((0, helpers_1.clamp)(v / srcMax, 0, 1) * dstMax));
13532
+ const cmyk = [0, 0, 0, 0];
13533
+ for (let i = 0, p = 0; i < size; i++, p += 4) {
13534
+ const a = data[p + 3];
13535
+ const alphaValue = convertAlpha(a);
13536
+ alpha[i] = alphaValue;
13537
+ // composite image colors are blended with white (or no ink) for documents with transparency
13538
+ const blend = matte && a !== srcMax && a > 0 ? (0, helpers_1.clamp)(a / srcMax, 0, 1) : 1;
13539
+ if (colorMode === 4 /* ColorMode.CMYK */) {
13540
+ (0, helpers_1.rgbToCmykValues)(toNormalized(data[p]), toNormalized(data[p + 1]), toNormalized(data[p + 2]), cmyk);
13541
+ for (let j = 0; j < 4; j++) {
13542
+ colors[j][i] = Math.round((1 - (0, helpers_1.clamp)(cmyk[j] * blend, 0, 1)) * dstMax); // stored inverted (0 = 100% ink)
13543
+ }
13544
+ }
13545
+ else {
13546
+ for (let j = 0; j < colorCount; j++) {
13547
+ let value;
13548
+ if (colorMode === 3 /* ColorMode.RGB */) {
13549
+ value = convertColor(data[p + j]);
13550
+ }
13551
+ else {
13552
+ const r = data[p], g = data[p + 1], b = data[p + 2];
13553
+ value = convertColor((r === g && g === b) ? r : (0.299 * r + 0.587 * g + 0.114 * b));
13554
+ }
13555
+ if (blend !== 1)
13556
+ value = dstFloat ? value * blend + 1 - blend : Math.round(value * blend + dstMax * (1 - blend));
13557
+ colors[j][i] = value;
13558
+ }
13559
+ }
13560
+ }
13561
+ return { colors, alpha };
13562
+ }
13563
+ function encodeChannel(values, width, height, options) {
13564
+ if (!(values instanceof Uint8Array)) {
13565
+ return { data: (0, helpers_1.writeDataZipWithPrediction)(values, width, height), compression: 3 /* Compression.ZipWithPrediction */ };
13566
+ }
13567
+ else if (options.compress) {
13568
+ return { data: (0, pako_1.deflate)(values), compression: 2 /* Compression.ZipWithoutPrediction */ };
13569
+ }
13570
+ else {
13571
+ return { data: (0, helpers_1.writeDataRLEBytes)(values, width, height, !!options.psb), compression: 1 /* Compression.RleCompressed */ };
13572
+ }
13573
+ }
13574
+ function writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, psb) {
13575
+ var _a;
13576
+ const { width, height } = psd;
13577
+ const data = imageData !== null && imageData !== void 0 ? imageData : { data: new Uint8Array(width * height * 4), width, height };
13578
+ const parts = [];
13579
+ if (colorMode === 0 /* ColorMode.Bitmap */ || colorMode === 2 /* ColorMode.Indexed */) {
13580
+ const values = colorMode === 0 /* ColorMode.Bitmap */ ?
13581
+ getBitmapData(data) :
13582
+ getIndexedData(data, psd.palette, (_a = psd.imageResources) === null || _a === void 0 ? void 0 : _a.transparencyIndex);
13583
+ const rowBytes = colorMode === 0 /* ColorMode.Bitmap */ ? Math.ceil(width / 8) : width;
13584
+ if (colorMode === 0 /* ColorMode.Bitmap */) {
13585
+ writeUint16(writer, 0 /* Compression.RawData */);
13586
+ parts.push(values);
13587
+ }
13588
+ else {
13589
+ writeUint16(writer, 1 /* Compression.RleCompressed */);
13590
+ parts.push((0, helpers_1.writeDataRLEBytes)(values, rowBytes, height, psb));
13591
+ }
13592
+ }
13593
+ else {
13594
+ const { colors, alpha } = getPlanarChannels(data, colorMode, bitsPerChannel, globalAlpha);
13595
+ const channels = globalAlpha ? [...colors, alpha] : colors;
13596
+ if (bitsPerChannel === 8) {
13597
+ // row byte counts for all channels are stored before data of all channels
13598
+ const encoded = channels.map(c => (0, helpers_1.writeDataRLEBytes)(c, width, height, psb));
13599
+ const countsSize = height * (psb ? 4 : 2);
13600
+ writeUint16(writer, 1 /* Compression.RleCompressed */);
13601
+ for (const e of encoded)
13602
+ parts.push(e.subarray(0, countsSize));
13603
+ for (const e of encoded)
13604
+ parts.push(e.subarray(countsSize));
13605
+ }
13606
+ else {
13607
+ writeUint16(writer, 0 /* Compression.RawData */); // Photoshop writes 16 and 32 bit composite image without compression
13608
+ for (const c of channels)
13609
+ parts.push((0, helpers_1.planarToBytes)(c));
13610
+ }
13611
+ }
13612
+ for (const part of parts)
13613
+ writeBytes(writer, part);
13614
+ }
13615
+ function getBitmapData({ data, width, height }) {
13616
+ const rowBytes = Math.ceil(width / 8);
13617
+ const result = new Uint8Array(rowBytes * height);
13618
+ const max = data instanceof Float32Array ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
13619
+ for (let y = 0, p = 0; y < height; y++) {
13620
+ for (let x = 0; x < width; x++, p += 4) {
13621
+ const a = data[p + 3] / max;
13622
+ const value = ((0.299 * data[p] + 0.587 * data[p + 1] + 0.114 * data[p + 2]) / max) * a + (1 - a); // blend with white
13623
+ if (value < 0.5)
13624
+ result[y * rowBytes + (x >> 3)] |= 0x80 >> (x & 7); // 1 = black
13625
+ }
13626
+ }
13627
+ return result;
13628
+ }
13629
+ function getIndexedData({ data, width, height }, palette, transparencyIndex) {
13630
+ const size = width * height;
13631
+ const result = new Uint8Array(size);
13632
+ const shift = data instanceof Uint16Array ? 8 : 0;
13633
+ const cache = new Map();
13634
+ for (let i = 0; i < palette.length && i < 256; i++) {
13635
+ const key = (palette[i].r << 16) | (palette[i].g << 8) | palette[i].b;
13636
+ if (i !== transparencyIndex && !cache.has(key))
13637
+ cache.set(key, i);
13638
+ }
13639
+ for (let i = 0, p = 0; i < size; i++, p += 4) {
13640
+ const read = (v) => data instanceof Float32Array ? Math.round(Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) * 255) : (v >>> shift);
13641
+ const a = data instanceof Float32Array ? data[p + 3] * 255 : (data[p + 3] >>> shift);
13642
+ if (transparencyIndex !== undefined && transparencyIndex >= 0 && a < 128) {
13643
+ result[i] = transparencyIndex;
13644
+ continue;
13645
+ }
13646
+ const r = read(data[p]), g = read(data[p + 1]), b = read(data[p + 2]);
13647
+ const key = (r << 16) | (g << 8) | b;
13648
+ let index = cache.get(key);
13649
+ if (index === undefined) {
13650
+ // use closest color from the palette
13651
+ let best = Infinity;
13652
+ index = 0;
13653
+ for (let j = 0; j < palette.length && j < 256; j++) {
13654
+ if (j === transparencyIndex)
13655
+ continue;
13656
+ const dr = palette[j].r - r, dg = palette[j].g - g, db = palette[j].b - b;
13657
+ const distance = dr * dr + dg * dg + db * db;
13658
+ if (distance < best) {
13659
+ best = distance;
13660
+ index = j;
13661
+ }
13662
+ }
13663
+ cache.set(key, index);
13664
+ }
13665
+ result[i] = index;
13666
+ }
13667
+ return result;
12613
13668
  }
12614
13669
  function getCompositeData(imageData, width, height, globalAlpha) {
12615
13670
  if (!imageData)
@@ -12635,60 +13690,61 @@ function getCompositeData(imageData, width, height, globalAlpha) {
12635
13690
  return dst ? { data: dst, width, height } : imageData;
12636
13691
  }
12637
13692
  function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
12638
- writeSection(writer, 4, () => {
12639
- var _a;
12640
- writeInt16(writer, globalAlpha ? -layers.length : layers.length);
12641
- const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
12642
- // layer records
12643
- for (const layerData of layersData) {
12644
- const { layer, top, left, bottom, right, channels } = layerData;
12645
- writeInt32(writer, top);
12646
- writeInt32(writer, left);
12647
- writeInt32(writer, bottom);
12648
- writeInt32(writer, right);
12649
- writeUint16(writer, channels.length);
12650
- for (const c of channels) {
12651
- writeInt16(writer, c.id);
12652
- if (options.psb) {
12653
- writeUint64(writer, c.length);
12654
- }
12655
- else {
12656
- writeUint32(writer, c.length);
12657
- }
13693
+ writeSection(writer, 4, () => writeLayerInfoData(writer, layers, psd, globalAlpha, options), true, options.psb);
13694
+ }
13695
+ function writeLayerInfoData(writer, layers, psd, globalAlpha, options) {
13696
+ var _a;
13697
+ writeInt16(writer, globalAlpha ? -layers.length : layers.length);
13698
+ const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
13699
+ // layer records
13700
+ for (const layerData of layersData) {
13701
+ const { layer, top, left, bottom, right, channels } = layerData;
13702
+ writeInt32(writer, top);
13703
+ writeInt32(writer, left);
13704
+ writeInt32(writer, bottom);
13705
+ writeInt32(writer, right);
13706
+ writeUint16(writer, channels.length);
13707
+ for (const c of channels) {
13708
+ writeInt16(writer, c.id);
13709
+ if (options.psb) {
13710
+ writeUint64(writer, c.length);
12658
13711
  }
12659
- writeSignature(writer, '8BIM');
12660
- writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
12661
- writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
12662
- writeUint8(writer, layer.clipping ? 1 : 0);
12663
- let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
12664
- if (layer.transparencyProtected)
12665
- flags |= 0x01;
12666
- if (layer.hidden)
12667
- flags |= 0x02;
12668
- if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
12669
- flags |= 0x10; // pixel data irrelevant to appearance of document
13712
+ else {
13713
+ writeUint32(writer, c.length);
12670
13714
  }
12671
- if (layer.effectsOpen)
12672
- flags |= 0x20;
12673
- writeUint8(writer, flags);
12674
- writeUint8(writer, 0); // filler
12675
- writeSection(writer, 1, () => {
12676
- writeLayerMaskData(writer, layer, layerData);
12677
- writeLayerBlendingRanges(writer, layer);
12678
- writePascalString(writer, (layer.name || '').substring(0, 255), 4);
12679
- writeAdditionalLayerInfo(writer, layer, psd, options);
12680
- });
12681
13715
  }
12682
- // layer channel image data
12683
- for (const layerData of layersData) {
12684
- for (const channel of layerData.channels) {
12685
- writeUint16(writer, channel.compression);
12686
- if (channel.data) {
12687
- writeBytes(writer, channel.data);
12688
- }
13716
+ writeSignature(writer, '8BIM');
13717
+ writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
13718
+ writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
13719
+ writeUint8(writer, layer.clipping ? 1 : 0);
13720
+ let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
13721
+ if (layer.transparencyProtected)
13722
+ flags |= 0x01;
13723
+ if (layer.hidden)
13724
+ flags |= 0x02;
13725
+ if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
13726
+ flags |= 0x10; // pixel data irrelevant to appearance of document
13727
+ }
13728
+ if (layer.effectsOpen)
13729
+ flags |= 0x20;
13730
+ writeUint8(writer, flags);
13731
+ writeUint8(writer, 0); // filler
13732
+ writeSection(writer, 1, () => {
13733
+ writeLayerMaskData(writer, layer, layerData);
13734
+ writeLayerBlendingRanges(writer, layer);
13735
+ writePascalString(writer, (layer.name || '').substring(0, 255), 4);
13736
+ writeAdditionalLayerInfo(writer, layer, psd, options);
13737
+ });
13738
+ }
13739
+ // layer channel image data
13740
+ for (const layerData of layersData) {
13741
+ for (const channel of layerData.channels) {
13742
+ writeUint16(writer, channel.compression);
13743
+ if (channel.data) {
13744
+ writeBytes(writer, channel.data);
12689
13745
  }
12690
13746
  }
12691
- }, true, options.psb);
13747
+ }
12692
13748
  }
12693
13749
  // real mask is only stored separately if layer has both vector and pixel masks, otherwise it's stored as the main mask
12694
13750
  function getMasks(layer) {
@@ -12891,6 +13947,7 @@ function createThumbnail(psd) {
12891
13947
  return canvas;
12892
13948
  }
12893
13949
  function getMaskChannels(tempBuffer, layerData, mask, options, realMask) {
13950
+ var _a;
12894
13951
  let top = mask.top | 0;
12895
13952
  let left = mask.left | 0;
12896
13953
  let right = mask.right | 0;
@@ -12907,10 +13964,15 @@ function getMaskChannels(tempBuffer, layerData, mask, options, realMask) {
12907
13964
  bottom = top + height;
12908
13965
  let buffer;
12909
13966
  let compression;
13967
+ const bitsPerChannel = (_a = options.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
12910
13968
  if (!imageData) {
12911
13969
  buffer = new Uint8Array(0);
12912
13970
  compression = 1 /* Compression.RleCompressed */;
12913
13971
  }
13972
+ else if (bitsPerChannel !== 8 || !is8bit(imageData)) {
13973
+ const { colors } = getPlanarChannels(imageData, 3 /* ColorMode.RGB */, bitsPerChannel, false);
13974
+ ({ data: buffer, compression } = encodeChannel(colors[0], width, height, options));
13975
+ }
12914
13976
  else if (options.compress) {
12915
13977
  buffer = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [0]);
12916
13978
  compression = 2 /* Compression.ZipWithoutPrediction */;
@@ -12931,16 +13993,16 @@ function bounds(obj) {
12931
13993
  } : undefined;
12932
13994
  }
12933
13995
  function getChannels(writer, layer, background, options) {
13996
+ var _a, _b;
12934
13997
  let source = layer;
12935
13998
  if (layer.rawData) {
12936
13999
  const { colorMode, bitsPerChannel, large } = layer.rawData;
12937
- if (large === !!options.psb && colorMode === 3 /* ColorMode.RGB */ && bitsPerChannel === 8) {
14000
+ const opt = options;
14001
+ if (large === !!options.psb && colorMode === ((_a = opt.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */) && bitsPerChannel === ((_b = opt.bitsPerChannel) !== null && _b !== void 0 ? _b : 8)) {
12938
14002
  // same mask mapping as in writeLayerMaskData
12939
14003
  const { mask, realMask } = getMasks(layer);
12940
14004
  return Object.assign(Object.assign({ layer, channels: layer.rawData.channels.map(c => { var _a, _b; return (Object.assign(Object.assign({}, c), { length: 2 + ((_b = (_a = c.data) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : 0) })); }) }, bounds(layer)), { mask: bounds(mask), realMask: bounds(realMask) });
12941
14005
  }
12942
- if (bitsPerChannel !== 8)
12943
- throw new Error('Layer raw data with bitsPerChannel other than 8 is not supported for writing');
12944
14006
  // raw data is in different format than the one we're writing, decode it so it can be re-encoded
12945
14007
  source = Object.assign(Object.assign({}, layer), { rawData: undefined, canvas: undefined, imageData: (0, psdReader_1.getLayerImageData)(layer), mask: layer.mask && Object.assign(Object.assign({}, layer.mask), { canvas: undefined, imageData: (0, psdReader_1.getLayerMaskImageData)(layer) }), realMask: layer.realMask && Object.assign(Object.assign({}, layer.realMask), { canvas: undefined, imageData: (0, psdReader_1.getLayerRealMaskImageData)(layer) }) });
12946
14008
  // temp buffer is sized only for layers with image data, grow it and keep it for following layers
@@ -12966,10 +14028,8 @@ function getLayerDimentions({ canvas, imageData }) {
12966
14028
  return { width, height };
12967
14029
  }
12968
14030
  function cropImageData(data, left, top, width, height) {
12969
- if (data.data instanceof Uint32Array || data.data instanceof Uint16Array) {
12970
- throw new Error('imageData has incorrect bit depth');
12971
- }
12972
- const croppedData = (0, helpers_1.createImageData)(width, height);
14031
+ const croppedData = is8bit(data) ? (0, helpers_1.createImageData)(width, height) :
14032
+ { width, height, data: new data.data.constructor(width * height * 4) };
12973
14033
  const srcData = data.data;
12974
14034
  const dstData = croppedData.data;
12975
14035
  for (let y = 0; y < height; y++) {
@@ -12985,6 +14045,7 @@ function cropImageData(data, left, top, width, height) {
12985
14045
  return croppedData;
12986
14046
  }
12987
14047
  function getLayerChannels(tempBuffer, layer, background, options) {
14048
+ var _a, _b;
12988
14049
  let top = layer.top | 0;
12989
14050
  let left = layer.left | 0;
12990
14051
  let right = layer.right | 0;
@@ -12997,8 +14058,11 @@ function getLayerChannels(tempBuffer, layer, background, options) {
12997
14058
  ];
12998
14059
  let { width, height } = getLayerDimentions(layer);
12999
14060
  if (!(layer.canvas || layer.imageData) || !width || !height) {
13000
- right = left;
13001
- bottom = top;
14061
+ // layer without image data is empty, keep inverted (negative size) bounds from some files as they are
14062
+ if (layer.right === undefined || right > left)
14063
+ right = left;
14064
+ if (layer.bottom === undefined || bottom > top)
14065
+ bottom = top;
13002
14066
  return { layer, top, left, right, bottom, channels };
13003
14067
  }
13004
14068
  right = left + width;
@@ -13026,6 +14090,19 @@ function getLayerChannels(tempBuffer, layer, background, options) {
13026
14090
  if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)) {
13027
14091
  channelIds.unshift(-1 /* ChannelID.Transparency */);
13028
14092
  }
14093
+ const colorMode = (_a = options.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
14094
+ const bitsPerChannel = (_b = options.bitsPerChannel) !== null && _b !== void 0 ? _b : 8;
14095
+ if (colorMode !== 3 /* ColorMode.RGB */ || bitsPerChannel !== 8 || !is8bit(imageData)) {
14096
+ const { colors, alpha } = getPlanarChannels(imageData, colorMode, bitsPerChannel, false);
14097
+ const ids = channelIds[0] === -1 /* ChannelID.Transparency */ ? [-1 /* ChannelID.Transparency */] : [];
14098
+ for (let i = 0; i < colors.length; i++)
14099
+ ids.push(i);
14100
+ channels = ids.map(id => {
14101
+ const { data, compression } = encodeChannel(id === -1 /* ChannelID.Transparency */ ? alpha : colors[id], width, height, options);
14102
+ return { id, compression, data, length: 2 + data.length };
14103
+ });
14104
+ return { layer, top, left, right, bottom, channels };
14105
+ }
13029
14106
  channels = channelIds.map(id => {
13030
14107
  const offset = (0, helpers_1.offsetForChannel)(id, false); // image data is always RGBA
13031
14108
  let data;
@@ -13183,10 +14260,11 @@ function writePattern(writer, pattern) {
13183
14260
  writer.view.setUint32(pattsOffset - 4, pattsLength, false);
13184
14261
  }
13185
14262
 
13186
- },{"./additionalInfo":2,"./helpers":8,"./imageResources":9,"./psdReader":13}],15:[function(require,module,exports){
14263
+ },{"./additionalInfo":2,"./helpers":9,"./imageResources":10,"./psdReader":14,"pako":21}],16:[function(require,module,exports){
13187
14264
  "use strict";
13188
14265
  Object.defineProperty(exports, "__esModule", { value: true });
13189
14266
  exports.decodeEngineData = decodeEngineData;
14267
+ exports.decodeLegacyTextData = decodeLegacyTextData;
13190
14268
  exports.encodeEngineData = encodeEngineData;
13191
14269
  const helpers_1 = require("./helpers");
13192
14270
  const defaultFont = {
@@ -13613,6 +14691,63 @@ function decodeEngineData(engineData) {
13613
14691
  delete result.styleRuns;
13614
14692
  return result;
13615
14693
  }
14694
+ const fixed = (value) => value / 0x10000; // 16.16 fixed point value
14695
+ function decodeLegacyTextData(data) {
14696
+ var _a, _b, _c, _d;
14697
+ const styleRuns = [];
14698
+ let text = '';
14699
+ for (const line of data.lines) {
14700
+ for (const { code, style } of line.chars) {
14701
+ text += String.fromCharCode(code);
14702
+ const last = styleRuns[styleRuns.length - 1];
14703
+ if (last && last.mark === style) {
14704
+ last.length++;
14705
+ }
14706
+ else {
14707
+ styleRuns.push({ length: 1, mark: style });
14708
+ }
14709
+ }
14710
+ }
14711
+ // remove one trailing new line (Photoshop always appends it)
14712
+ if (text.endsWith('\r')) {
14713
+ text = text.slice(0, -1);
14714
+ if (--styleRuns[styleRuns.length - 1].length === 0)
14715
+ styleRuns.pop();
14716
+ }
14717
+ const runs = styleRuns.map(({ length, mark }) => {
14718
+ var _a, _b;
14719
+ const s = (_a = data.styles.find(s => s.mark === mark)) !== null && _a !== void 0 ? _a : data.styles[0];
14720
+ const face = s && ((_b = data.faces.find(f => f.mark === s.faceMark)) !== null && _b !== void 0 ? _b : data.faces[0]);
14721
+ const style = {};
14722
+ if (face)
14723
+ style.font = { name: face.name, script: face.script };
14724
+ if (s) {
14725
+ style.fontSize = fixed(s.size);
14726
+ style.autoLeading = s.leading === 0;
14727
+ if (s.leading)
14728
+ style.leading = fixed(s.leading);
14729
+ style.tracking = Math.round(fixed(s.tracking) * 1000); // stored in ems
14730
+ style.autoKerning = s.autoKerning;
14731
+ style.kerning = Math.round(fixed(s.kerning) * 1000); // stored in ems
14732
+ style.baselineShift = fixed(s.baselineShift);
14733
+ }
14734
+ style.fillColor = data.color;
14735
+ return { length, style };
14736
+ });
14737
+ const result = {
14738
+ text: text.replace(/\r/g, '\n'),
14739
+ transform: data.transform,
14740
+ antiAlias: data.antiAlias ? 'smooth' : 'none',
14741
+ orientation: ((_a = data.lines[0]) === null || _a === void 0 ? void 0 : _a.orientation) === 1 ? 'vertical' : 'horizontal',
14742
+ paragraphStyle: { justification: (_d = justification[(_c = (_b = data.lines[0]) === null || _b === void 0 ? void 0 : _b.alignment) !== null && _c !== void 0 ? _c : 0]) !== null && _d !== void 0 ? _d : 'left' },
14743
+ style: {},
14744
+ styleRuns: runs,
14745
+ };
14746
+ deduplicateValues(result.style, result.styleRuns, styleKeys);
14747
+ if (!result.styleRuns.length)
14748
+ delete result.styleRuns;
14749
+ return result;
14750
+ }
13616
14751
  // Adjusts run lengths (specified in terms of the original text) for characters removed from the text
13617
14752
  // (\r characters of \r\n pairs that are collapsed into single \r)
13618
14753
  function adjustRunLengths(runs, removed) {
@@ -13851,7 +14986,7 @@ function encodeEngineData(data) {
13851
14986
  return engineData;
13852
14987
  }
13853
14988
 
13854
- },{"./helpers":8}],16:[function(require,module,exports){
14989
+ },{"./helpers":9}],17:[function(require,module,exports){
13855
14990
  "use strict";
13856
14991
  Object.defineProperty(exports, "__esModule", { value: true });
13857
14992
  exports.stringLengthInBytes = stringLengthInBytes;
@@ -14038,7 +15173,7 @@ function decodeString(value) {
14038
15173
  return result.join('');
14039
15174
  }
14040
15175
 
14041
- },{}],17:[function(require,module,exports){
15176
+ },{}],18:[function(require,module,exports){
14042
15177
  'use strict'
14043
15178
 
14044
15179
  exports.byteLength = byteLength
@@ -14190,7 +15325,7 @@ function fromByteArray (uint8) {
14190
15325
  return parts.join('')
14191
15326
  }
14192
15327
 
14193
- },{}],18:[function(require,module,exports){
15328
+ },{}],19:[function(require,module,exports){
14194
15329
  (function (Buffer){(function (){
14195
15330
  /*!
14196
15331
  * The buffer module from node.js, for the browser.
@@ -15971,7 +17106,7 @@ function numberIsNaN (obj) {
15971
17106
  }
15972
17107
 
15973
17108
  }).call(this)}).call(this,require("buffer").Buffer)
15974
- },{"base64-js":17,"buffer":18,"ieee754":19}],19:[function(require,module,exports){
17109
+ },{"base64-js":18,"buffer":19,"ieee754":20}],20:[function(require,module,exports){
15975
17110
  /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
15976
17111
  exports.read = function (buffer, offset, isLE, mLen, nBytes) {
15977
17112
  var e, m
@@ -16058,7 +17193,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
16058
17193
  buffer[offset + i - d] |= s * 128
16059
17194
  }
16060
17195
 
16061
- },{}],20:[function(require,module,exports){
17196
+ },{}],21:[function(require,module,exports){
16062
17197
  // Top level file is just a mixin of submodules & constants
16063
17198
  'use strict';
16064
17199
 
@@ -16078,7 +17213,7 @@ module.exports.inflateRaw = inflateRaw;
16078
17213
  module.exports.ungzip = ungzip;
16079
17214
  module.exports.constants = constants;
16080
17215
 
16081
- },{"./lib/deflate":21,"./lib/inflate":22,"./lib/zlib/constants":26}],21:[function(require,module,exports){
17216
+ },{"./lib/deflate":22,"./lib/inflate":23,"./lib/zlib/constants":27}],22:[function(require,module,exports){
16082
17217
  'use strict';
16083
17218
 
16084
17219
 
@@ -16460,7 +17595,7 @@ module.exports.deflateRaw = deflateRaw;
16460
17595
  module.exports.gzip = gzip;
16461
17596
  module.exports.constants = require('./zlib/constants');
16462
17597
 
16463
- },{"./utils/common":23,"./utils/strings":24,"./zlib/constants":26,"./zlib/deflate":28,"./zlib/messages":33,"./zlib/zstream":35}],22:[function(require,module,exports){
17598
+ },{"./utils/common":24,"./utils/strings":25,"./zlib/constants":27,"./zlib/deflate":29,"./zlib/messages":34,"./zlib/zstream":36}],23:[function(require,module,exports){
16464
17599
  'use strict';
16465
17600
 
16466
17601
 
@@ -16881,7 +18016,7 @@ module.exports.inflateRaw = inflateRaw;
16881
18016
  module.exports.ungzip = inflate;
16882
18017
  module.exports.constants = require('./zlib/constants');
16883
18018
 
16884
- },{"./utils/common":23,"./utils/strings":24,"./zlib/constants":26,"./zlib/gzheader":29,"./zlib/inflate":31,"./zlib/messages":33,"./zlib/zstream":35}],23:[function(require,module,exports){
18019
+ },{"./utils/common":24,"./utils/strings":25,"./zlib/constants":27,"./zlib/gzheader":30,"./zlib/inflate":32,"./zlib/messages":34,"./zlib/zstream":36}],24:[function(require,module,exports){
16885
18020
  'use strict';
16886
18021
 
16887
18022
 
@@ -16931,7 +18066,7 @@ module.exports.flattenChunks = (chunks) => {
16931
18066
  return result;
16932
18067
  };
16933
18068
 
16934
- },{}],24:[function(require,module,exports){
18069
+ },{}],25:[function(require,module,exports){
16935
18070
  // String encode/decode helpers
16936
18071
  'use strict';
16937
18072
 
@@ -17107,7 +18242,7 @@ module.exports.utf8border = (buf, max) => {
17107
18242
  return (pos + _utf8len[buf[pos]] > max) ? pos : max;
17108
18243
  };
17109
18244
 
17110
- },{}],25:[function(require,module,exports){
18245
+ },{}],26:[function(require,module,exports){
17111
18246
  'use strict';
17112
18247
 
17113
18248
  // Note: adler32 takes 12% for level 0 and 2% for level 6.
@@ -17160,7 +18295,7 @@ const adler32 = (adler, buf, len, pos) => {
17160
18295
 
17161
18296
  module.exports = adler32;
17162
18297
 
17163
- },{}],26:[function(require,module,exports){
18298
+ },{}],27:[function(require,module,exports){
17164
18299
  'use strict';
17165
18300
 
17166
18301
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -17230,7 +18365,7 @@ module.exports = {
17230
18365
  //Z_NULL: null // Use -1 or null inline, depending on var type
17231
18366
  };
17232
18367
 
17233
- },{}],27:[function(require,module,exports){
18368
+ },{}],28:[function(require,module,exports){
17234
18369
  'use strict';
17235
18370
 
17236
18371
  // Note: we can't get significant speed boost here.
@@ -17291,7 +18426,7 @@ const crc32 = (crc, buf, len, pos) => {
17291
18426
 
17292
18427
  module.exports = crc32;
17293
18428
 
17294
- },{}],28:[function(require,module,exports){
18429
+ },{}],29:[function(require,module,exports){
17295
18430
  'use strict';
17296
18431
 
17297
18432
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -19341,7 +20476,7 @@ module.exports.deflatePrime = deflatePrime;
19341
20476
  module.exports.deflateTune = deflateTune;
19342
20477
  */
19343
20478
 
19344
- },{"./adler32":25,"./constants":26,"./crc32":27,"./messages":33,"./trees":34}],29:[function(require,module,exports){
20479
+ },{"./adler32":26,"./constants":27,"./crc32":28,"./messages":34,"./trees":35}],30:[function(require,module,exports){
19345
20480
  'use strict';
19346
20481
 
19347
20482
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -19401,7 +20536,7 @@ function GZheader() {
19401
20536
 
19402
20537
  module.exports = GZheader;
19403
20538
 
19404
- },{}],30:[function(require,module,exports){
20539
+ },{}],31:[function(require,module,exports){
19405
20540
  'use strict';
19406
20541
 
19407
20542
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -19747,7 +20882,7 @@ module.exports = function inflate_fast(strm, start) {
19747
20882
  return;
19748
20883
  };
19749
20884
 
19750
- },{}],31:[function(require,module,exports){
20885
+ },{}],32:[function(require,module,exports){
19751
20886
  'use strict';
19752
20887
 
19753
20888
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -21321,7 +22456,7 @@ module.exports.inflateUndermine = inflateUndermine;
21321
22456
  module.exports.inflateValidate = inflateValidate;
21322
22457
  */
21323
22458
 
21324
- },{"./adler32":25,"./constants":26,"./crc32":27,"./inffast":30,"./inftrees":32}],32:[function(require,module,exports){
22459
+ },{"./adler32":26,"./constants":27,"./crc32":28,"./inffast":31,"./inftrees":33}],33:[function(require,module,exports){
21325
22460
  'use strict';
21326
22461
 
21327
22462
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -21663,7 +22798,7 @@ const inflate_table = (type, lens, lens_index, codes, table, table_index, work,
21663
22798
 
21664
22799
  module.exports = inflate_table;
21665
22800
 
21666
- },{}],33:[function(require,module,exports){
22801
+ },{}],34:[function(require,module,exports){
21667
22802
  'use strict';
21668
22803
 
21669
22804
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -21697,7 +22832,7 @@ module.exports = {
21697
22832
  '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
21698
22833
  };
21699
22834
 
21700
- },{}],34:[function(require,module,exports){
22835
+ },{}],35:[function(require,module,exports){
21701
22836
  'use strict';
21702
22837
 
21703
22838
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -22878,7 +24013,7 @@ module.exports._tr_flush_block = _tr_flush_block;
22878
24013
  module.exports._tr_tally = _tr_tally;
22879
24014
  module.exports._tr_align = _tr_align;
22880
24015
 
22881
- },{}],35:[function(require,module,exports){
24016
+ },{}],36:[function(require,module,exports){
22882
24017
  'use strict';
22883
24018
 
22884
24019
  // (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -22927,5 +24062,5 @@ function ZStream() {
22927
24062
 
22928
24063
  module.exports = ZStream;
22929
24064
 
22930
- },{}]},{},[10])(10)
24065
+ },{}]},{},[11])(11)
22931
24066
  });