ag-psd 32.0.0 → 33.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 (103) 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/932f0770 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  22. package/CHANGELOG.md +78 -0
  23. package/LICENSE +5 -0
  24. package/README.md +3 -6
  25. package/README_PSD.md +242 -81
  26. package/dist/abr.d.ts +11 -4
  27. package/dist/abr.js +357 -230
  28. package/dist/abr.js.map +1 -1
  29. package/dist/additionalInfo.d.ts +54 -2
  30. package/dist/additionalInfo.js +487 -306
  31. package/dist/additionalInfo.js.map +1 -1
  32. package/dist/ase.d.ts +6 -1
  33. package/dist/ase.js +61 -61
  34. package/dist/ase.js.map +1 -1
  35. package/dist/bundle.js +1937 -1115
  36. package/dist/descriptor.d.ts +14 -8
  37. package/dist/descriptor.js +202 -186
  38. package/dist/descriptor.js.map +1 -1
  39. package/dist/helpers.d.ts +1 -1
  40. package/dist/helpers.js +4 -2
  41. package/dist/helpers.js.map +1 -1
  42. package/dist/imageResources.d.ts +15 -3
  43. package/dist/imageResources.js +503 -142
  44. package/dist/imageResources.js.map +1 -1
  45. package/dist/jpeg.js +8 -8
  46. package/dist/jpeg.js.map +1 -1
  47. package/dist/psd.d.ts +148 -17
  48. package/dist/psd.js.map +1 -1
  49. package/dist/psdReader.d.ts +10 -0
  50. package/dist/psdReader.js +278 -166
  51. package/dist/psdReader.js.map +1 -1
  52. package/dist/psdWriter.d.ts +1 -0
  53. package/dist/psdWriter.js +77 -62
  54. package/dist/psdWriter.js.map +1 -1
  55. package/dist/text.js +17 -6
  56. package/dist/text.js.map +1 -1
  57. package/dist/utf8.js +0 -3
  58. package/dist/utf8.js.map +1 -1
  59. package/dist-es/abr.d.ts +11 -4
  60. package/dist-es/abr.js +357 -230
  61. package/dist-es/abr.js.map +1 -1
  62. package/dist-es/additionalInfo.d.ts +54 -2
  63. package/dist-es/additionalInfo.js +487 -306
  64. package/dist-es/additionalInfo.js.map +1 -1
  65. package/dist-es/ase.d.ts +6 -1
  66. package/dist-es/ase.js +61 -61
  67. package/dist-es/ase.js.map +1 -1
  68. package/dist-es/descriptor.d.ts +14 -8
  69. package/dist-es/descriptor.js +202 -186
  70. package/dist-es/descriptor.js.map +1 -1
  71. package/dist-es/helpers.d.ts +1 -1
  72. package/dist-es/helpers.js +4 -2
  73. package/dist-es/helpers.js.map +1 -1
  74. package/dist-es/imageResources.d.ts +15 -3
  75. package/dist-es/imageResources.js +503 -142
  76. package/dist-es/imageResources.js.map +1 -1
  77. package/dist-es/jpeg.js +8 -8
  78. package/dist-es/jpeg.js.map +1 -1
  79. package/dist-es/psd.d.ts +148 -17
  80. package/dist-es/psd.js.map +1 -1
  81. package/dist-es/psdReader.d.ts +10 -0
  82. package/dist-es/psdReader.js +278 -166
  83. package/dist-es/psdReader.js.map +1 -1
  84. package/dist-es/psdWriter.d.ts +1 -0
  85. package/dist-es/psdWriter.js +77 -62
  86. package/dist-es/psdWriter.js.map +1 -1
  87. package/dist-es/text.js +17 -6
  88. package/dist-es/text.js.map +1 -1
  89. package/dist-es/utf8.js +0 -3
  90. package/dist-es/utf8.js.map +1 -1
  91. package/package.json +2 -2
  92. package/src/abr.ts +375 -235
  93. package/src/additionalInfo.ts +663 -420
  94. package/src/ase.ts +66 -61
  95. package/src/descriptor.ts +199 -195
  96. package/src/helpers.ts +4 -1
  97. package/src/imageResources.ts +632 -168
  98. package/src/jpeg.ts +8 -8
  99. package/src/psd.ts +156 -30
  100. package/src/psdReader.ts +273 -172
  101. package/src/psdWriter.ts +95 -58
  102. package/src/text.ts +17 -6
  103. package/src/utf8.ts +0 -4
package/dist/abr.d.ts CHANGED
@@ -85,6 +85,7 @@ interface DynamicBrushShape {
85
85
  }
86
86
  export interface Brush {
87
87
  name: string;
88
+ group?: string[];
88
89
  shape: BrushShape;
89
90
  shapeDynamics?: {
90
91
  sizeDynamics: BrushDynamics;
@@ -138,8 +139,8 @@ export interface Brush {
138
139
  transfer?: {
139
140
  flowDynamics: BrushDynamics;
140
141
  opacityDynamics: BrushDynamics;
141
- wetnessDynamics: BrushDynamics;
142
- mixDynamics: BrushDynamics;
142
+ wetnessDynamics?: BrushDynamics;
143
+ mixDynamics?: BrushDynamics;
143
144
  };
144
145
  brushPose?: {
145
146
  overrideAngle: boolean;
@@ -153,6 +154,7 @@ export interface Brush {
153
154
  };
154
155
  noise: boolean;
155
156
  wetEdges: boolean;
157
+ buildUp: boolean;
156
158
  protectTexture?: boolean;
157
159
  spacing: number;
158
160
  brushGroup?: undefined;
@@ -190,7 +192,12 @@ export interface Brush {
190
192
  strength?: number;
191
193
  };
192
194
  }
193
- export declare function readAbr(buffer: ArrayBufferView, options?: {
195
+ export interface ReadAbrOptions {
194
196
  logMissingFeatures?: boolean;
195
- }): Abr;
197
+ /** Throw on unsupported or invalid parts of the file instead of skipping them */
198
+ throwForMissingFeatures?: boolean;
199
+ /** Memory limit for decoded data in bytes (2GB by default), set to `undefined` explicitly to disable */
200
+ totalMemoryLimit?: number;
201
+ }
202
+ export declare function readAbr(buffer: ArrayBufferView, options?: ReadAbrOptions): Abr;
196
203
  export {};
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,302 @@ 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 * (compression === 1 && 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
+ if (compression === 0) {
262
+ for (let i = 0; i < alpha.byteLength; i++) {
263
+ alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
264
+ }
265
+ }
266
+ else if (compression === 1) {
267
+ const data = new Uint16Array(w * h);
268
+ (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data }, w, h, bithDepth, 1, [0], false);
269
+ for (let i = 0; i < alpha.byteLength; i++) {
270
+ alpha[i] = data[i] >> 8; // convert to 8bit values
271
+ }
272
+ }
273
+ else {
274
+ throw new Error('Invalid compression');
275
+ }
276
+ }
277
+ else {
278
+ throw new Error('Invalid depth');
279
+ }
280
+ return { id, bounds: { x, y, w, h }, alpha };
281
+ }
282
+ // ABR versions 1 and 2 (Photoshop 6 and earlier) contain a list of brushes with brush tips in them
283
+ function readLegacyBrushes(reader, version, samples, brushes, skip) {
284
+ const count = (0, psdReader_1.readUint16)(reader);
285
+ for (let i = 0; i < count; i++) {
286
+ const type = (0, psdReader_1.readUint16)(reader);
287
+ const size = (0, psdReader_1.readUint32)(reader);
288
+ const end = reader.offset + size;
289
+ if (end > reader.view.byteLength) { // truncated file
290
+ skip(new Error('Brush data out of bounds'), `brush ${i + 1}`);
291
+ break;
292
+ }
293
+ try {
294
+ if (type === 1) { // computed brush
295
+ (0, psdReader_1.skipBytes)(reader, 4); // misc
296
+ const spacing = (0, psdReader_1.readUint16)(reader);
297
+ const diameter = (0, psdReader_1.readUint16)(reader);
298
+ const roundness = (0, psdReader_1.readUint16)(reader);
299
+ const angle = (0, psdReader_1.readInt16)(reader);
300
+ const hardness = (0, psdReader_1.readUint16)(reader);
301
+ if (reader.offset > end)
302
+ throw new Error('Brush data out of bounds');
303
+ brushes.push(createLegacyBrush('', {
304
+ type: 'computed',
305
+ size: diameter,
306
+ angle,
307
+ roundness: roundness / 100,
308
+ spacingOn: spacing !== 0,
309
+ spacing: spacing / 100,
310
+ flipX: false,
311
+ flipY: false,
312
+ hardness: hardness / 100,
313
+ }));
314
+ }
315
+ else if (type === 2) { // sampled brush
316
+ (0, psdReader_1.skipBytes)(reader, 4); // misc
317
+ const spacing = (0, psdReader_1.readUint16)(reader);
318
+ const name = version === 2 ? (0, psdReader_1.readUnicodeString)(reader) : '';
319
+ (0, psdReader_1.skipBytes)(reader, 1 + 8); // antialiasing, Int16 bounds rectangle (same as Int32 one)
320
+ // legacy brushes don't have sample ids
321
+ const sample = readSampleBitmap(reader, end, `brush-${i + 1}`);
322
+ samples.push(sample);
323
+ brushes.push(createLegacyBrush(name, {
324
+ type: 'sampled',
325
+ size: Math.max(sample.bounds.w, sample.bounds.h),
326
+ angle: 0,
327
+ roundness: 1,
328
+ spacingOn: spacing !== 0,
329
+ spacing: spacing / 100,
330
+ flipX: false,
331
+ flipY: false,
332
+ name,
333
+ sampledData: sample.id,
334
+ }));
335
+ }
336
+ else {
337
+ throw new Error(`Unknown brush type: ${type}`);
338
+ }
339
+ }
340
+ catch (e) {
341
+ skip(e, `brush ${i + 1}`);
342
+ }
343
+ reader.offset = end;
344
+ }
345
+ }
346
+ function createLegacyBrush(name, shape) {
347
+ return { name, shape, spacing: 1, wetEdges: false, noise: false, buildUp: false, useBrushSize: true };
348
+ }
349
+ function parseBrush(brush) {
350
+ var _a, _b, _c;
351
+ const b = {
352
+ name: brush['Nm '],
353
+ shape: parseBrushShape(brush.Brsh),
354
+ spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
355
+ wetEdges: brush.Wtdg,
356
+ noise: brush.Nose,
357
+ buildUp: !!brush['Rpt '],
358
+ useBrushSize: brush.useBrushSize, // ???
359
+ };
360
+ if (brush.interpretation != null)
361
+ b.interpretation = brush.interpretation;
362
+ if (brush.protectTexture != null)
363
+ b.protectTexture = brush.protectTexture;
364
+ if (brush.useTipDynamics) {
365
+ b.shapeDynamics = {
366
+ tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
367
+ sizeDynamics: parseDynamics(brush.szVr),
368
+ angleDynamics: parseDynamics(brush.angleDynamics),
369
+ roundnessDynamics: parseDynamics(brush.roundnessDynamics),
370
+ flipX: brush.flipX,
371
+ flipY: brush.flipY,
372
+ brushProjection: brush.brushProjection,
373
+ minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
374
+ minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
375
+ };
376
+ }
377
+ if (brush.useScatter) {
378
+ b.scatter = {
379
+ count: brush['Cnt '],
380
+ bothAxes: brush.bothAxes,
381
+ countDynamics: parseDynamics(brush.countDynamics),
382
+ scatterDynamics: parseDynamics(brush.scatterDynamics),
383
+ };
384
+ }
385
+ if (brush.useTexture && brush.Txtr) {
386
+ b.texture = {
387
+ id: brush.Txtr.Idnt,
388
+ name: brush.Txtr['Nm '],
389
+ blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
390
+ depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
391
+ depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
392
+ depthDynamics: parseDynamics(brush.textureDepthDynamics),
393
+ scale: (0, descriptor_1.parsePercent)(brush.textureScale),
394
+ invert: brush.InvT,
395
+ brightness: brush.textureBrightness,
396
+ contrast: brush.textureContrast,
397
+ textureEachTip: !!brush.TxtC,
398
+ };
399
+ }
400
+ const db = brush.dualBrush;
401
+ if (db && db.useDualBrush) {
402
+ b.dualBrush = {
403
+ flip: db.Flip,
404
+ shape: parseBrushShape(db.Brsh),
405
+ blendMode: descriptor_1.BlnM.decode(db.BlnM),
406
+ useScatter: db.useScatter,
407
+ spacing: (0, descriptor_1.parsePercent)(db.Spcn),
408
+ count: db['Cnt '],
409
+ bothAxes: db.bothAxes,
410
+ countDynamics: parseDynamics(db.countDynamics),
411
+ scatterDynamics: parseDynamics(db.scatterDynamics),
412
+ };
413
+ }
414
+ if (brush.useColorDynamics) {
415
+ b.colorDynamics = {
416
+ foregroundBackground: parseDynamics(brush.clVr),
417
+ hue: (0, descriptor_1.parsePercent)(brush['H ']),
418
+ saturation: (0, descriptor_1.parsePercent)(brush.Strt),
419
+ brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
420
+ purity: (0, descriptor_1.parsePercent)(brush.purity),
421
+ perTip: brush.colorDynamicsPerTip,
422
+ };
423
+ }
424
+ if (brush.usePaintDynamics) {
425
+ b.transfer = {
426
+ flowDynamics: parseDynamics(brush.prVr),
427
+ opacityDynamics: parseDynamics(brush.opVr),
428
+ };
429
+ if (brush.wtVr)
430
+ b.transfer.wetnessDynamics = parseDynamics(brush.wtVr);
431
+ if (brush.mxVr)
432
+ b.transfer.mixDynamics = parseDynamics(brush.mxVr);
433
+ }
434
+ if (brush.useBrushPose) {
435
+ b.brushPose = {
436
+ overrideAngle: brush.overridePoseAngle,
437
+ overrideTiltX: brush.overridePoseTiltX,
438
+ overrideTiltY: brush.overridePoseTiltY,
439
+ overridePressure: brush.overridePosePressure,
440
+ pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
441
+ tiltX: brush.brushPoseTiltX,
442
+ tiltY: brush.brushPoseTiltY,
443
+ angle: brush.brushPoseAngle,
444
+ };
445
+ }
446
+ const to = brush.toolOptions;
447
+ if (to) {
448
+ b.toolOptions = {
449
+ type: toBrushType[to._classID] || 'brush',
450
+ brushPreset: to.brushPreset,
451
+ flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
452
+ smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
453
+ mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
454
+ opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
455
+ smoothing: !!to.smoothing,
456
+ smoothingValue: to.smoothingValue || 0,
457
+ smoothingRadiusMode: !!to.smoothingRadiusMode,
458
+ smoothingCatchup: !!to.smoothingCatchup,
459
+ smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
460
+ smoothingZoomCompensation: !!to.smoothingZoomCompensation,
461
+ pressureSmoothing: !!to.pressureSmoothing,
462
+ usePressureOverridesSize: !!to.usePressureOverridesSize,
463
+ usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
464
+ useLegacy: !!to.useLegacy,
465
+ };
466
+ if (to.prVr)
467
+ b.toolOptions.flowDynamics = parseDynamics(to.prVr);
468
+ if (to.opVr)
469
+ b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
470
+ if (to.szVr)
471
+ b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
472
+ if ('wetness' in to)
473
+ b.toolOptions.wetness = to.wetness;
474
+ if ('dryness' in to)
475
+ b.toolOptions.dryness = to.dryness;
476
+ if ('mix' in to)
477
+ b.toolOptions.mix = to.mix;
478
+ if ('autoFill' in to)
479
+ b.toolOptions.autoFill = to.autoFill;
480
+ if ('autoClean' in to)
481
+ b.toolOptions.autoClean = to.autoClean;
482
+ if ('loadSolidColorOnly' in to)
483
+ b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
484
+ if ('sampleAllLayers' in to)
485
+ b.toolOptions.sampleAllLayers = to.sampleAllLayers;
486
+ if ('SmdF' in to)
487
+ b.toolOptions.smudgeFingerPainting = to.SmdF;
488
+ if ('SmdS' in to)
489
+ b.toolOptions.smudgeSampleAllLayers = to.SmdS;
490
+ if ('Prs ' in to)
491
+ b.toolOptions.strength = to['Prs '];
492
+ }
493
+ return b;
494
+ }
368
495
  //# sourceMappingURL=abr.js.map