ag-psd 32.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 (117) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/d13d7610 +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  22. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  23. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  24. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  25. package/CHANGELOG.md +100 -0
  26. package/LICENSE +5 -0
  27. package/README.md +4 -7
  28. package/README_PSD.md +261 -84
  29. package/TODO.md +13 -84
  30. package/dist/abr.d.ts +11 -4
  31. package/dist/abr.js +362 -230
  32. package/dist/abr.js.map +1 -1
  33. package/dist/additionalInfo.d.ts +56 -2
  34. package/dist/additionalInfo.js +828 -361
  35. package/dist/additionalInfo.js.map +1 -1
  36. package/dist/ase.d.ts +6 -1
  37. package/dist/ase.js +61 -61
  38. package/dist/ase.js.map +1 -1
  39. package/dist/bundle.js +3321 -1364
  40. package/dist/descriptor.d.ts +28 -13
  41. package/dist/descriptor.js +295 -241
  42. package/dist/descriptor.js.map +1 -1
  43. package/dist/helpers.d.ts +7 -1
  44. package/dist/helpers.js +246 -4
  45. package/dist/helpers.js.map +1 -1
  46. package/dist/imageResources.d.ts +15 -3
  47. package/dist/imageResources.js +586 -144
  48. package/dist/imageResources.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +1 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/jpeg.js +8 -8
  53. package/dist/jpeg.js.map +1 -1
  54. package/dist/psd.d.ts +292 -19
  55. package/dist/psd.js.map +1 -1
  56. package/dist/psdReader.d.ts +10 -0
  57. package/dist/psdReader.js +424 -216
  58. package/dist/psdReader.js.map +1 -1
  59. package/dist/psdWriter.d.ts +2 -0
  60. package/dist/psdWriter.js +373 -113
  61. package/dist/psdWriter.js.map +1 -1
  62. package/dist/text.d.ts +32 -1
  63. package/dist/text.js +75 -6
  64. package/dist/text.js.map +1 -1
  65. package/dist/utf8.js +0 -3
  66. package/dist/utf8.js.map +1 -1
  67. package/dist-es/abr.d.ts +11 -4
  68. package/dist-es/abr.js +362 -230
  69. package/dist-es/abr.js.map +1 -1
  70. package/dist-es/additionalInfo.d.ts +56 -2
  71. package/dist-es/additionalInfo.js +828 -361
  72. package/dist-es/additionalInfo.js.map +1 -1
  73. package/dist-es/ase.d.ts +6 -1
  74. package/dist-es/ase.js +61 -61
  75. package/dist-es/ase.js.map +1 -1
  76. package/dist-es/descriptor.d.ts +28 -13
  77. package/dist-es/descriptor.js +295 -241
  78. package/dist-es/descriptor.js.map +1 -1
  79. package/dist-es/helpers.d.ts +7 -1
  80. package/dist-es/helpers.js +246 -4
  81. package/dist-es/helpers.js.map +1 -1
  82. package/dist-es/imageResources.d.ts +15 -3
  83. package/dist-es/imageResources.js +586 -144
  84. package/dist-es/imageResources.js.map +1 -1
  85. package/dist-es/index.d.ts +1 -0
  86. package/dist-es/index.js +1 -0
  87. package/dist-es/index.js.map +1 -1
  88. package/dist-es/jpeg.js +8 -8
  89. package/dist-es/jpeg.js.map +1 -1
  90. package/dist-es/psd.d.ts +292 -19
  91. package/dist-es/psd.js.map +1 -1
  92. package/dist-es/psdReader.d.ts +10 -0
  93. package/dist-es/psdReader.js +424 -216
  94. package/dist-es/psdReader.js.map +1 -1
  95. package/dist-es/psdWriter.d.ts +2 -0
  96. package/dist-es/psdWriter.js +373 -113
  97. package/dist-es/psdWriter.js.map +1 -1
  98. package/dist-es/text.d.ts +32 -1
  99. package/dist-es/text.js +75 -6
  100. package/dist-es/text.js.map +1 -1
  101. package/dist-es/utf8.js +0 -3
  102. package/dist-es/utf8.js.map +1 -1
  103. package/package.json +2 -2
  104. package/perf.js +312 -9
  105. package/src/abr.ts +382 -235
  106. package/src/additionalInfo.ts +1071 -482
  107. package/src/ase.ts +66 -61
  108. package/src/descriptor.ts +291 -242
  109. package/src/helpers.ts +266 -3
  110. package/src/imageResources.ts +736 -169
  111. package/src/index.ts +1 -0
  112. package/src/jpeg.ts +8 -8
  113. package/src/psd.ts +271 -32
  114. package/src/psdReader.ts +440 -221
  115. package/src/psdWriter.ts +402 -110
  116. package/src/text.ts +93 -7
  117. package/src/utf8.ts +0 -4
package/dist/abr.js CHANGED
@@ -98,261 +98,92 @@ function parseHeightmap(array) {
98
98
  // return result;
99
99
  }
100
100
  function readAbr(buffer, options = {}) {
101
- var _a, _b, _c, _d;
102
101
  const reader = (0, psdReader_1.createReader)(buffer.buffer, buffer.byteOffset, buffer.byteLength);
102
+ reader.logMissingFeatures = options.logMissingFeatures;
103
+ reader.throwForMissingFeatures = options.throwForMissingFeatures;
104
+ reader.totalMemoryLimit = 'totalMemoryLimit' in options ? options.totalMemoryLimit : 2 * 1024 * 1024 * 1024;
105
+ // skips invalid or unsupported part of the file
106
+ const skip = (e, what) => {
107
+ if (options.throwForMissingFeatures)
108
+ throw e;
109
+ options.logMissingFeatures && reader.log(`Skipped ${what}: ${e.message}`);
110
+ };
111
+ if (reader.view.byteLength < 4)
112
+ throw new Error('Invalid ABR file');
103
113
  const version = (0, psdReader_1.readInt16)(reader);
104
114
  const samples = [];
105
115
  const brushes = [];
106
116
  const patterns = [];
117
+ const brushByPreset = []; // brush for each preset in 'desc' section (brushes that fail to parse are skipped)
118
+ let hierarchy;
107
119
  if (version === 1 || version === 2) {
108
- throw new Error(`Unsupported ABR version (${version})`); // TODO: ...
120
+ readLegacyBrushes(reader, version, samples, brushes, skip);
109
121
  }
110
122
  else if (version === 6 || version === 7 || version === 9 || version === 10) {
111
123
  const minorVersion = (0, psdReader_1.readInt16)(reader);
112
124
  if (minorVersion !== 1 && minorVersion !== 2)
113
125
  throw new Error('Unsupported ABR minor version');
114
- while (reader.offset < reader.view.byteLength) {
126
+ // section header is 12 bytes, ignore any shorter trailing data
127
+ while (reader.offset + 12 <= reader.view.byteLength) {
115
128
  (0, psdReader_1.checkSignature)(reader, '8BIM');
116
129
  const type = (0, psdReader_1.readSignature)(reader);
117
130
  const size = (0, psdReader_1.readUint32)(reader);
118
- const end = reader.offset + size;
119
- switch (type) {
120
- case 'samp': {
121
- while (reader.offset < end) {
122
- let brushLength = (0, psdReader_1.readUint32)(reader);
123
- while (brushLength & 0b11)
124
- brushLength++; // pad to 4 byte alignment
125
- const brushEnd = reader.offset + brushLength;
126
- const id = (0, psdReader_1.readPascalString)(reader, 1);
127
- // v1 - Skip the Int16 bounds rectangle and the unknown Int16.
128
- // v2 - Skip the unknown bytes.
129
- (0, psdReader_1.skipBytes)(reader, minorVersion === 1 ? 10 : 264);
130
- const y = (0, psdReader_1.readInt32)(reader);
131
- const x = (0, psdReader_1.readInt32)(reader);
132
- const h = (0, psdReader_1.readInt32)(reader) - y;
133
- const w = (0, psdReader_1.readInt32)(reader) - x;
134
- if (w <= 0 || h <= 0)
135
- throw new Error('Invalid bounds');
136
- if (w > MAX_BRUSH_SIZE || h > MAX_BRUSH_SIZE) {
137
- throw new Error(`Brush sample too large (${w}x${h})`);
138
- }
139
- const bithDepth = (0, psdReader_1.readInt16)(reader);
140
- const compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
141
- if (compression === 0 && w * h * (bithDepth === 16 ? 2 : 1) > brushEnd - reader.offset) {
142
- throw new Error('Brush sample data out of bounds');
143
- }
144
- const alpha = new Uint8Array(w * h);
145
- if (bithDepth === 8) {
146
- if (compression === 0) {
147
- alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
148
- }
149
- else if (compression === 1) {
150
- (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
131
+ const end = Math.min(reader.offset + size, reader.view.byteLength);
132
+ try {
133
+ switch (type) {
134
+ case 'samp': {
135
+ while (reader.offset + 4 <= end) {
136
+ let brushLength = (0, psdReader_1.readUint32)(reader);
137
+ while (brushLength & 0b11)
138
+ brushLength++; // pad to 4 byte alignment
139
+ const brushEnd = Math.min(reader.offset + brushLength, end);
140
+ try {
141
+ const sample = readSample(reader, brushEnd, minorVersion);
142
+ samples.push(sample);
151
143
  }
152
- else {
153
- throw new Error('Invalid compression');
144
+ catch (e) {
145
+ skip(e, 'brush sample');
154
146
  }
147
+ reader.offset = brushEnd;
155
148
  }
156
- else if (bithDepth === 16) {
157
- if (compression === 0) {
158
- for (let i = 0; i < alpha.byteLength; i++) {
159
- alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
160
- }
161
- }
162
- else if (compression === 1) {
163
- throw new Error('not implemented (16bit RLE)'); // TODO: ...
149
+ break;
150
+ }
151
+ case 'desc': {
152
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
153
+ for (const [index, brush] of (desc.Brsh || []).entries()) {
154
+ try {
155
+ const parsed = parseBrush(brush);
156
+ brushes.push(parsed);
157
+ brushByPreset[index] = parsed;
164
158
  }
165
- else {
166
- throw new Error('Invalid compression');
159
+ catch (e) {
160
+ skip(e, `brush "${brush['Nm ']}"`);
167
161
  }
168
162
  }
169
- else {
170
- throw new Error('Invalid depth');
171
- }
172
- samples.push({ id, bounds: { x, y, w, h }, alpha });
173
- reader.offset = brushEnd;
163
+ break;
174
164
  }
175
- break;
176
- }
177
- case 'desc': {
178
- const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
179
- // console.log(require('util').inspect(desc, false, 99, true));
180
- // require('fs').writeFileSync('test.log', require('util').inspect(desc, false, 99, false), 'utf8');
181
- for (const brush of desc.Brsh) {
182
- const b = {
183
- name: brush['Nm '],
184
- shape: parseBrushShape(brush.Brsh),
185
- spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
186
- // TODO: brushGroup ???
187
- wetEdges: brush.Wtdg,
188
- noise: brush.Nose,
189
- // TODO: TxtC ??? smoothing / build-up ?
190
- // TODO: 'Rpt ' ???
191
- useBrushSize: brush.useBrushSize, // ???
192
- };
193
- if (brush.interpretation != null)
194
- b.interpretation = brush.interpretation;
195
- if (brush.protectTexture != null)
196
- b.protectTexture = brush.protectTexture;
197
- if (brush.useTipDynamics) {
198
- b.shapeDynamics = {
199
- tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
200
- sizeDynamics: parseDynamics(brush.szVr),
201
- angleDynamics: parseDynamics(brush.angleDynamics),
202
- roundnessDynamics: parseDynamics(brush.roundnessDynamics),
203
- flipX: brush.flipX,
204
- flipY: brush.flipY,
205
- brushProjection: brush.brushProjection,
206
- minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
207
- minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
208
- };
209
- }
210
- if (brush.useScatter) {
211
- b.scatter = {
212
- count: brush['Cnt '],
213
- bothAxes: brush.bothAxes,
214
- countDynamics: parseDynamics(brush.countDynamics),
215
- scatterDynamics: parseDynamics(brush.scatterDynamics),
216
- };
217
- }
218
- if (brush.useTexture && brush.Txtr) {
219
- b.texture = {
220
- id: brush.Txtr.Idnt,
221
- name: brush.Txtr['Nm '],
222
- blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
223
- depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
224
- depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
225
- depthDynamics: parseDynamics(brush.textureDepthDynamics),
226
- scale: (0, descriptor_1.parsePercent)(brush.textureScale),
227
- invert: brush.InvT,
228
- brightness: brush.textureBrightness,
229
- contrast: brush.textureContrast,
230
- textureEachTip: !!brush.TxtC,
231
- };
232
- }
233
- const db = brush.dualBrush;
234
- if (db && db.useDualBrush) {
235
- b.dualBrush = {
236
- flip: db.Flip,
237
- shape: parseBrushShape(db.Brsh),
238
- blendMode: descriptor_1.BlnM.decode(db.BlnM),
239
- useScatter: db.useScatter,
240
- spacing: (0, descriptor_1.parsePercent)(db.Spcn),
241
- count: db['Cnt '],
242
- bothAxes: db.bothAxes,
243
- countDynamics: parseDynamics(db.countDynamics),
244
- scatterDynamics: parseDynamics(db.scatterDynamics),
245
- };
246
- }
247
- if (brush.useColorDynamics) {
248
- b.colorDynamics = {
249
- foregroundBackground: parseDynamics(brush.clVr),
250
- hue: (0, descriptor_1.parsePercent)(brush['H ']),
251
- saturation: (0, descriptor_1.parsePercent)(brush.Strt),
252
- brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
253
- purity: (0, descriptor_1.parsePercent)(brush.purity),
254
- perTip: brush.colorDynamicsPerTip,
255
- };
256
- }
257
- if (brush.usePaintDynamics) {
258
- b.transfer = {
259
- flowDynamics: parseDynamics(brush.prVr),
260
- opacityDynamics: parseDynamics(brush.opVr),
261
- wetnessDynamics: parseDynamics(brush.wtVr),
262
- mixDynamics: parseDynamics(brush.mxVr),
263
- };
264
- }
265
- if (brush.useBrushPose) {
266
- b.brushPose = {
267
- overrideAngle: brush.overridePoseAngle,
268
- overrideTiltX: brush.overridePoseTiltX,
269
- overrideTiltY: brush.overridePoseTiltY,
270
- overridePressure: brush.overridePosePressure,
271
- pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
272
- tiltX: brush.brushPoseTiltX,
273
- tiltY: brush.brushPoseTiltY,
274
- angle: brush.brushPoseAngle,
275
- };
276
- }
277
- const to = brush.toolOptions;
278
- if (to) {
279
- b.toolOptions = {
280
- type: toBrushType[to._classID] || 'brush',
281
- brushPreset: to.brushPreset,
282
- flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
283
- smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
284
- mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
285
- opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
286
- smoothing: !!to.smoothing,
287
- smoothingValue: to.smoothingValue || 0,
288
- smoothingRadiusMode: !!to.smoothingRadiusMode,
289
- smoothingCatchup: !!to.smoothingCatchup,
290
- smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
291
- smoothingZoomCompensation: !!to.smoothingZoomCompensation,
292
- pressureSmoothing: !!to.pressureSmoothing,
293
- usePressureOverridesSize: !!to.usePressureOverridesSize,
294
- usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
295
- useLegacy: !!to.useLegacy,
296
- };
297
- if (to.prVr)
298
- b.toolOptions.flowDynamics = parseDynamics(to.prVr);
299
- if (to.opVr)
300
- b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
301
- if (to.szVr)
302
- b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
303
- if ('wetness' in to)
304
- b.toolOptions.wetness = to.wetness;
305
- if ('dryness' in to)
306
- b.toolOptions.dryness = to.dryness;
307
- if ('mix' in to)
308
- b.toolOptions.mix = to.mix;
309
- if ('autoFill' in to)
310
- b.toolOptions.autoFill = to.autoFill;
311
- if ('autoClean' in to)
312
- b.toolOptions.autoClean = to.autoClean;
313
- if ('loadSolidColorOnly' in to)
314
- b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
315
- if ('sampleAllLayers' in to)
316
- b.toolOptions.sampleAllLayers = to.sampleAllLayers;
317
- if ('SmdF' in to)
318
- b.toolOptions.smudgeFingerPainting = to.SmdF;
319
- if ('SmdS' in to)
320
- b.toolOptions.smudgeSampleAllLayers = to.SmdS;
321
- if ('Prs ' in to)
322
- b.toolOptions.strength = to['Prs '];
165
+ case 'patt': {
166
+ while (reader.offset + 4 <= end) {
167
+ const pattern = (0, psdReader_1.readPatternSafe)(reader);
168
+ if (pattern)
169
+ patterns.push(pattern);
323
170
  }
324
- brushes.push(b);
171
+ break;
325
172
  }
326
- break;
327
- }
328
- case 'patt': {
329
- while (reader.offset < end) {
330
- patterns.push((0, psdReader_1.readPattern)(reader));
331
- }
332
- reader.offset = end;
333
- break;
334
- }
335
- case 'phry': {
336
- // TODO: what is this ?
337
- const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
338
- // example:
339
- // hierarchy: [
340
- // {
341
- // 'Nm ': 'PRE_EXPORT ',
342
- // zuid: '965209f2-6f35-9a40-aa43-485684382172'
343
- // },
344
- // {},
345
- // ...
346
- // ]
347
- if (options.logMissingFeatures) {
348
- if ((_d = desc.hierarchy) === null || _d === void 0 ? void 0 : _d.length) {
349
- // console.log('unhandled phry section', desc);
350
- }
173
+ case 'phry': { // brush groups (folders in brushes panel)
174
+ // flat list of group starts, presets (in the same order as in 'desc' section) and group ends
175
+ const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
176
+ hierarchy = desc.hierarchy;
177
+ break;
351
178
  }
352
- break;
179
+ default:
180
+ // 'lPdc' (tool presets) and other unknown sections
181
+ options.logMissingFeatures && reader.log(`Unhandled brush section: ${type}`);
182
+ break;
353
183
  }
354
- default:
355
- throw new Error(`Invalid brush type: ${type}`);
184
+ }
185
+ catch (e) {
186
+ skip(e, `brush section ${type}`);
356
187
  }
357
188
  // skip any unread data in the section and align to 4 bytes
358
189
  reader.offset = end;
@@ -363,6 +194,307 @@ function readAbr(buffer, options = {}) {
363
194
  else {
364
195
  throw new Error(`Unsupported ABR version (${version})`);
365
196
  }
197
+ if (hierarchy) {
198
+ const groups = [];
199
+ let presetIndex = 0;
200
+ for (const item of hierarchy) {
201
+ if (item._classID === 'Grup') {
202
+ groups.push(item['Nm ']);
203
+ }
204
+ else if (item._classID === 'groupEnd') {
205
+ groups.pop();
206
+ }
207
+ else if (item._classID === 'preset') {
208
+ const brush = brushByPreset[presetIndex];
209
+ if (brush && groups.length)
210
+ brush.group = groups.slice();
211
+ presetIndex++;
212
+ }
213
+ }
214
+ }
366
215
  return { samples, patterns, brushes };
367
216
  }
217
+ function readSample(reader, brushEnd, minorVersion) {
218
+ const id = (0, psdReader_1.readPascalString)(reader, 1);
219
+ // v1 - Skip the Int16 bounds rectangle and the unknown Int16.
220
+ // v2 - Skip the unknown bytes.
221
+ (0, psdReader_1.skipBytes)(reader, minorVersion === 1 ? 10 : 264);
222
+ return readSampleBitmap(reader, brushEnd, id);
223
+ }
224
+ // bounds, bit depth, compression and image data of brush sample
225
+ function readSampleBitmap(reader, brushEnd, id) {
226
+ const y = (0, psdReader_1.readInt32)(reader);
227
+ const x = (0, psdReader_1.readInt32)(reader);
228
+ const h = (0, psdReader_1.readInt32)(reader) - y;
229
+ const w = (0, psdReader_1.readInt32)(reader) - x;
230
+ if (w <= 0 || h <= 0)
231
+ throw new Error('Invalid bounds');
232
+ if (w > MAX_BRUSH_SIZE || h > MAX_BRUSH_SIZE) {
233
+ throw new Error(`Brush sample too large (${w}x${h})`);
234
+ }
235
+ const bithDepth = (0, psdReader_1.readInt16)(reader);
236
+ const compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
237
+ if (bithDepth !== 8 && bithDepth !== 16)
238
+ throw new Error('Invalid depth');
239
+ if (compression !== 0 && compression !== 1)
240
+ throw new Error('Invalid compression');
241
+ const rowSize = w * (bithDepth === 16 ? 2 : 1);
242
+ // RLE needs at least 2 bytes for row length and 2 bytes per each 128 byte run
243
+ const minDataSize = compression === 0 ? h * rowSize : h * (2 + Math.ceil(rowSize / 128) * 2);
244
+ if (minDataSize > brushEnd - reader.offset) {
245
+ throw new Error('Brush sample data out of bounds');
246
+ }
247
+ (0, psdReader_1.consumeMemory)(reader, w * h * (bithDepth === 16 ? 3 : 1));
248
+ const alpha = new Uint8Array(w * h);
249
+ if (bithDepth === 8) {
250
+ if (compression === 0) {
251
+ alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
252
+ }
253
+ else if (compression === 1) {
254
+ (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
255
+ }
256
+ else {
257
+ throw new Error('Invalid compression');
258
+ }
259
+ }
260
+ else if (bithDepth === 16) {
261
+ const data = new Uint16Array(w * h);
262
+ if (compression === 0) {
263
+ for (let i = 0; i < data.length; i++) {
264
+ data[i] = (0, psdReader_1.readUint16)(reader);
265
+ }
266
+ }
267
+ else if (compression === 1) {
268
+ (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data }, w, h, bithDepth, 1, [0], false);
269
+ }
270
+ else {
271
+ throw new Error('Invalid compression');
272
+ }
273
+ // Photoshop uses 0-32768 range for 16bit values internally, use full 0-65535 range only if there are values outside of it
274
+ let max = 0;
275
+ for (let i = 0; i < data.length; i++)
276
+ max = Math.max(max, data[i]);
277
+ const scale = max > 32768 ? 255 / 65535 : 255 / 32768;
278
+ for (let i = 0; i < alpha.byteLength; i++) {
279
+ alpha[i] = Math.round(data[i] * scale); // convert to 8bit values
280
+ }
281
+ }
282
+ else {
283
+ throw new Error('Invalid depth');
284
+ }
285
+ return { id, bounds: { x, y, w, h }, alpha };
286
+ }
287
+ // ABR versions 1 and 2 (Photoshop 6 and earlier) contain a list of brushes with brush tips in them
288
+ function readLegacyBrushes(reader, version, samples, brushes, skip) {
289
+ const count = (0, psdReader_1.readUint16)(reader);
290
+ for (let i = 0; i < count; i++) {
291
+ const type = (0, psdReader_1.readUint16)(reader);
292
+ const size = (0, psdReader_1.readUint32)(reader);
293
+ const end = reader.offset + size;
294
+ if (end > reader.view.byteLength) { // truncated file
295
+ skip(new Error('Brush data out of bounds'), `brush ${i + 1}`);
296
+ break;
297
+ }
298
+ try {
299
+ if (type === 1) { // computed brush
300
+ (0, psdReader_1.skipBytes)(reader, 4); // misc
301
+ const spacing = (0, psdReader_1.readUint16)(reader);
302
+ const diameter = (0, psdReader_1.readUint16)(reader);
303
+ const roundness = (0, psdReader_1.readUint16)(reader);
304
+ const angle = (0, psdReader_1.readInt16)(reader);
305
+ const hardness = (0, psdReader_1.readUint16)(reader);
306
+ if (reader.offset > end)
307
+ throw new Error('Brush data out of bounds');
308
+ brushes.push(createLegacyBrush('', {
309
+ type: 'computed',
310
+ size: diameter,
311
+ angle,
312
+ roundness: roundness / 100,
313
+ spacingOn: spacing !== 0,
314
+ spacing: spacing / 100,
315
+ flipX: false,
316
+ flipY: false,
317
+ hardness: hardness / 100,
318
+ }));
319
+ }
320
+ else if (type === 2) { // sampled brush
321
+ (0, psdReader_1.skipBytes)(reader, 4); // misc
322
+ const spacing = (0, psdReader_1.readUint16)(reader);
323
+ const name = version === 2 ? (0, psdReader_1.readUnicodeString)(reader) : '';
324
+ (0, psdReader_1.skipBytes)(reader, 1 + 8); // antialiasing, Int16 bounds rectangle (same as Int32 one)
325
+ // legacy brushes don't have sample ids
326
+ const sample = readSampleBitmap(reader, end, `brush-${i + 1}`);
327
+ samples.push(sample);
328
+ brushes.push(createLegacyBrush(name, {
329
+ type: 'sampled',
330
+ size: Math.max(sample.bounds.w, sample.bounds.h),
331
+ angle: 0,
332
+ roundness: 1,
333
+ spacingOn: spacing !== 0,
334
+ spacing: spacing / 100,
335
+ flipX: false,
336
+ flipY: false,
337
+ name,
338
+ sampledData: sample.id,
339
+ }));
340
+ }
341
+ else {
342
+ throw new Error(`Unknown brush type: ${type}`);
343
+ }
344
+ }
345
+ catch (e) {
346
+ skip(e, `brush ${i + 1}`);
347
+ }
348
+ reader.offset = end;
349
+ }
350
+ }
351
+ function createLegacyBrush(name, shape) {
352
+ return { name, shape, spacing: 1, wetEdges: false, noise: false, buildUp: false, useBrushSize: true };
353
+ }
354
+ function parseBrush(brush) {
355
+ var _a, _b, _c;
356
+ const b = {
357
+ name: brush['Nm '],
358
+ shape: parseBrushShape(brush.Brsh),
359
+ spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
360
+ wetEdges: brush.Wtdg,
361
+ noise: brush.Nose,
362
+ buildUp: !!brush['Rpt '],
363
+ useBrushSize: brush.useBrushSize, // ???
364
+ };
365
+ if (brush.interpretation != null)
366
+ b.interpretation = brush.interpretation;
367
+ if (brush.protectTexture != null)
368
+ b.protectTexture = brush.protectTexture;
369
+ if (brush.useTipDynamics) {
370
+ b.shapeDynamics = {
371
+ tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
372
+ sizeDynamics: parseDynamics(brush.szVr),
373
+ angleDynamics: parseDynamics(brush.angleDynamics),
374
+ roundnessDynamics: parseDynamics(brush.roundnessDynamics),
375
+ flipX: brush.flipX,
376
+ flipY: brush.flipY,
377
+ brushProjection: brush.brushProjection,
378
+ minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
379
+ minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
380
+ };
381
+ }
382
+ if (brush.useScatter) {
383
+ b.scatter = {
384
+ count: brush['Cnt '],
385
+ bothAxes: brush.bothAxes,
386
+ countDynamics: parseDynamics(brush.countDynamics),
387
+ scatterDynamics: parseDynamics(brush.scatterDynamics),
388
+ };
389
+ }
390
+ if (brush.useTexture && brush.Txtr) {
391
+ b.texture = {
392
+ id: brush.Txtr.Idnt,
393
+ name: brush.Txtr['Nm '],
394
+ blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
395
+ depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
396
+ depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
397
+ depthDynamics: parseDynamics(brush.textureDepthDynamics),
398
+ scale: (0, descriptor_1.parsePercent)(brush.textureScale),
399
+ invert: brush.InvT,
400
+ brightness: brush.textureBrightness,
401
+ contrast: brush.textureContrast,
402
+ textureEachTip: !!brush.TxtC,
403
+ };
404
+ }
405
+ const db = brush.dualBrush;
406
+ if (db && db.useDualBrush) {
407
+ b.dualBrush = {
408
+ flip: db.Flip,
409
+ shape: parseBrushShape(db.Brsh),
410
+ blendMode: descriptor_1.BlnM.decode(db.BlnM),
411
+ useScatter: db.useScatter,
412
+ spacing: (0, descriptor_1.parsePercent)(db.Spcn),
413
+ count: db['Cnt '],
414
+ bothAxes: db.bothAxes,
415
+ countDynamics: parseDynamics(db.countDynamics),
416
+ scatterDynamics: parseDynamics(db.scatterDynamics),
417
+ };
418
+ }
419
+ if (brush.useColorDynamics) {
420
+ b.colorDynamics = {
421
+ foregroundBackground: parseDynamics(brush.clVr),
422
+ hue: (0, descriptor_1.parsePercent)(brush['H ']),
423
+ saturation: (0, descriptor_1.parsePercent)(brush.Strt),
424
+ brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
425
+ purity: (0, descriptor_1.parsePercent)(brush.purity),
426
+ perTip: brush.colorDynamicsPerTip,
427
+ };
428
+ }
429
+ if (brush.usePaintDynamics) {
430
+ b.transfer = {
431
+ flowDynamics: parseDynamics(brush.prVr),
432
+ opacityDynamics: parseDynamics(brush.opVr),
433
+ };
434
+ if (brush.wtVr)
435
+ b.transfer.wetnessDynamics = parseDynamics(brush.wtVr);
436
+ if (brush.mxVr)
437
+ b.transfer.mixDynamics = parseDynamics(brush.mxVr);
438
+ }
439
+ if (brush.useBrushPose) {
440
+ b.brushPose = {
441
+ overrideAngle: brush.overridePoseAngle,
442
+ overrideTiltX: brush.overridePoseTiltX,
443
+ overrideTiltY: brush.overridePoseTiltY,
444
+ overridePressure: brush.overridePosePressure,
445
+ pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
446
+ tiltX: brush.brushPoseTiltX,
447
+ tiltY: brush.brushPoseTiltY,
448
+ angle: brush.brushPoseAngle,
449
+ };
450
+ }
451
+ const to = brush.toolOptions;
452
+ if (to) {
453
+ b.toolOptions = {
454
+ type: toBrushType[to._classID] || 'brush',
455
+ brushPreset: to.brushPreset,
456
+ flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
457
+ smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
458
+ mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
459
+ opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
460
+ smoothing: !!to.smoothing,
461
+ smoothingValue: to.smoothingValue || 0,
462
+ smoothingRadiusMode: !!to.smoothingRadiusMode,
463
+ smoothingCatchup: !!to.smoothingCatchup,
464
+ smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
465
+ smoothingZoomCompensation: !!to.smoothingZoomCompensation,
466
+ pressureSmoothing: !!to.pressureSmoothing,
467
+ usePressureOverridesSize: !!to.usePressureOverridesSize,
468
+ usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
469
+ useLegacy: !!to.useLegacy,
470
+ };
471
+ if (to.prVr)
472
+ b.toolOptions.flowDynamics = parseDynamics(to.prVr);
473
+ if (to.opVr)
474
+ b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
475
+ if (to.szVr)
476
+ b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
477
+ if ('wetness' in to)
478
+ b.toolOptions.wetness = to.wetness;
479
+ if ('dryness' in to)
480
+ b.toolOptions.dryness = to.dryness;
481
+ if ('mix' in to)
482
+ b.toolOptions.mix = to.mix;
483
+ if ('autoFill' in to)
484
+ b.toolOptions.autoFill = to.autoFill;
485
+ if ('autoClean' in to)
486
+ b.toolOptions.autoClean = to.autoClean;
487
+ if ('loadSolidColorOnly' in to)
488
+ b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
489
+ if ('sampleAllLayers' in to)
490
+ b.toolOptions.sampleAllLayers = to.sampleAllLayers;
491
+ if ('SmdF' in to)
492
+ b.toolOptions.smudgeFingerPainting = to.SmdF;
493
+ if ('SmdS' in to)
494
+ b.toolOptions.smudgeSampleAllLayers = to.SmdS;
495
+ if ('Prs ' in to)
496
+ b.toolOptions.strength = to['Prs '];
497
+ }
498
+ return b;
499
+ }
368
500
  //# sourceMappingURL=abr.js.map