ag-psd 31.0.3 → 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 (159) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/00d0e0b4 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/0cc76730 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/20729831 +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/214a593b +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/25f8b84a +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/27518289 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/330ef2d9 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/37ff16b8 +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/3f72a97c +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/75efccd4 +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/762f9305 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/7bcfc50a +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  22. package/.v8-cache/v24.7.0-x64-ef5a0af0/825e9a05 +0 -0
  23. package/.v8-cache/v24.7.0-x64-ef5a0af0/87372817 +0 -0
  24. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  25. package/.v8-cache/v24.7.0-x64-ef5a0af0/891a7c73 +0 -0
  26. package/.v8-cache/v24.7.0-x64-ef5a0af0/8b68a3a2 +0 -0
  27. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  28. package/.v8-cache/v24.7.0-x64-ef5a0af0/a1d12a93 +0 -0
  29. package/.v8-cache/v24.7.0-x64-ef5a0af0/a7e80865 +0 -0
  30. package/.v8-cache/v24.7.0-x64-ef5a0af0/ac317c9c +0 -0
  31. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  32. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  33. package/.v8-cache/v24.7.0-x64-ef5a0af0/b8569d6b +0 -0
  34. package/.v8-cache/v24.7.0-x64-ef5a0af0/b8b073c4 +0 -0
  35. package/.v8-cache/v24.7.0-x64-ef5a0af0/bb489c89 +0 -0
  36. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  37. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  38. package/.v8-cache/v24.7.0-x64-ef5a0af0/c46725e1 +0 -0
  39. package/.v8-cache/v24.7.0-x64-ef5a0af0/c794cb34 +0 -0
  40. package/.v8-cache/v24.7.0-x64-ef5a0af0/cd4ae980 +0 -0
  41. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  42. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  43. package/.v8-cache/v24.7.0-x64-ef5a0af0/d02dd6f7 +0 -0
  44. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  45. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  46. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6735171 +0 -0
  47. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  48. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  49. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  50. package/.v8-cache/v24.7.0-x64-ef5a0af0/f5417276 +0 -0
  51. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  52. package/.v8-cache/v24.7.0-x64-ef5a0af0/f74d3518 +0 -0
  53. package/.v8-cache/v24.7.0-x64-ef5a0af0/f886deac +0 -0
  54. package/.v8-cache/v24.7.0-x64-ef5a0af0/fd0a2987 +0 -0
  55. package/.v8-cache/v24.7.0-x64-ef5a0af0/fe349423 +0 -0
  56. package/CHANGELOG.md +107 -0
  57. package/LICENSE +5 -0
  58. package/README.md +3 -6
  59. package/README_PSD.md +242 -81
  60. package/dist/abr.d.ts +11 -4
  61. package/dist/abr.js +363 -229
  62. package/dist/abr.js.map +1 -1
  63. package/dist/additionalInfo.d.ts +56 -2
  64. package/dist/additionalInfo.js +600 -364
  65. package/dist/additionalInfo.js.map +1 -1
  66. package/dist/ase.d.ts +6 -1
  67. package/dist/ase.js +61 -61
  68. package/dist/ase.js.map +1 -1
  69. package/dist/bundle.js +3096 -1541
  70. package/dist/descriptor.d.ts +25 -6
  71. package/dist/descriptor.js +380 -135
  72. package/dist/descriptor.js.map +1 -1
  73. package/dist/effectsHelpers.js +12 -12
  74. package/dist/effectsHelpers.js.map +1 -1
  75. package/dist/engineData.d.ts +3 -1
  76. package/dist/engineData.js +34 -13
  77. package/dist/engineData.js.map +1 -1
  78. package/dist/engineData2.js +50 -21
  79. package/dist/engineData2.js.map +1 -1
  80. package/dist/helpers.d.ts +6 -3
  81. package/dist/helpers.js +22 -6
  82. package/dist/helpers.js.map +1 -1
  83. package/dist/imageResources.d.ts +15 -3
  84. package/dist/imageResources.js +529 -144
  85. package/dist/imageResources.js.map +1 -1
  86. package/dist/index.js +1 -0
  87. package/dist/index.js.map +1 -1
  88. package/dist/jpeg.js +30 -10
  89. package/dist/jpeg.js.map +1 -1
  90. package/dist/psd.d.ts +154 -18
  91. package/dist/psd.js.map +1 -1
  92. package/dist/psdReader.d.ts +12 -2
  93. package/dist/psdReader.js +720 -421
  94. package/dist/psdReader.js.map +1 -1
  95. package/dist/psdWriter.d.ts +3 -0
  96. package/dist/psdWriter.js +167 -130
  97. package/dist/psdWriter.js.map +1 -1
  98. package/dist/text.js +143 -29
  99. package/dist/text.js.map +1 -1
  100. package/dist/utf8.js +36 -18
  101. package/dist/utf8.js.map +1 -1
  102. package/dist-es/abr.d.ts +11 -4
  103. package/dist-es/abr.js +363 -229
  104. package/dist-es/abr.js.map +1 -1
  105. package/dist-es/additionalInfo.d.ts +56 -2
  106. package/dist-es/additionalInfo.js +600 -364
  107. package/dist-es/additionalInfo.js.map +1 -1
  108. package/dist-es/ase.d.ts +6 -1
  109. package/dist-es/ase.js +61 -61
  110. package/dist-es/ase.js.map +1 -1
  111. package/dist-es/descriptor.d.ts +25 -6
  112. package/dist-es/descriptor.js +380 -135
  113. package/dist-es/descriptor.js.map +1 -1
  114. package/dist-es/effectsHelpers.js +12 -12
  115. package/dist-es/effectsHelpers.js.map +1 -1
  116. package/dist-es/engineData.d.ts +3 -1
  117. package/dist-es/engineData.js +34 -13
  118. package/dist-es/engineData.js.map +1 -1
  119. package/dist-es/engineData2.js +50 -21
  120. package/dist-es/engineData2.js.map +1 -1
  121. package/dist-es/helpers.d.ts +6 -3
  122. package/dist-es/helpers.js +22 -6
  123. package/dist-es/helpers.js.map +1 -1
  124. package/dist-es/imageResources.d.ts +15 -3
  125. package/dist-es/imageResources.js +529 -144
  126. package/dist-es/imageResources.js.map +1 -1
  127. package/dist-es/index.js +1 -0
  128. package/dist-es/index.js.map +1 -1
  129. package/dist-es/jpeg.js +30 -10
  130. package/dist-es/jpeg.js.map +1 -1
  131. package/dist-es/psd.d.ts +154 -18
  132. package/dist-es/psd.js.map +1 -1
  133. package/dist-es/psdReader.d.ts +12 -2
  134. package/dist-es/psdReader.js +720 -421
  135. package/dist-es/psdReader.js.map +1 -1
  136. package/dist-es/psdWriter.d.ts +3 -0
  137. package/dist-es/psdWriter.js +167 -130
  138. package/dist-es/psdWriter.js.map +1 -1
  139. package/dist-es/text.js +143 -29
  140. package/dist-es/text.js.map +1 -1
  141. package/dist-es/utf8.js +36 -18
  142. package/dist-es/utf8.js.map +1 -1
  143. package/package.json +2 -2
  144. package/src/abr.ts +380 -232
  145. package/src/additionalInfo.ts +781 -477
  146. package/src/ase.ts +66 -61
  147. package/src/descriptor.ts +386 -142
  148. package/src/effectsHelpers.ts +9 -9
  149. package/src/engineData.ts +36 -13
  150. package/src/engineData2.ts +468 -432
  151. package/src/helpers.ts +23 -5
  152. package/src/imageResources.ts +658 -167
  153. package/src/index.ts +1 -0
  154. package/src/jpeg.ts +27 -12
  155. package/src/psd.ts +158 -30
  156. package/src/psdReader.ts +732 -414
  157. package/src/psdWriter.ts +186 -132
  158. package/src/text.ts +139 -18
  159. package/src/utf8.ts +35 -21
package/dist-es/abr.js CHANGED
@@ -6,6 +6,8 @@ const psdReader_1 = require("./psdReader");
6
6
  const dynamicsControl = ['off', 'fade', 'pen pressure', 'pen tilt', 'stylus wheel', 'initial direction', 'direction', 'initial rotation', 'rotation'];
7
7
  const dynamicBrushShapeShapes = ['round point', 'round blunt', 'round curve', 'round angle', 'round fan', 'flat point', 'flat blunt', 'flat curve', 'flat angle', 'flat fan'];
8
8
  const tipsBrushShapeShapes = ['erodible point', 'erodible flat', 'erodible round', 'erodible square', 'erodible triangle', 'custom'];
9
+ // sanity limits for brush sample dimensions (Photoshop brushes are limited to 5000px)
10
+ const MAX_BRUSH_SIZE = 10000;
9
11
  const toBrushType = {
10
12
  _: 'brush',
11
13
  MixB: 'mixer brush',
@@ -96,266 +98,398 @@ function parseHeightmap(array) {
96
98
  // return result;
97
99
  }
98
100
  function readAbr(buffer, options = {}) {
99
- var _a, _b, _c, _d;
100
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');
101
113
  const version = (0, psdReader_1.readInt16)(reader);
102
114
  const samples = [];
103
115
  const brushes = [];
104
116
  const patterns = [];
117
+ const brushByPreset = []; // brush for each preset in 'desc' section (brushes that fail to parse are skipped)
118
+ let hierarchy;
105
119
  if (version === 1 || version === 2) {
106
- throw new Error(`Unsupported ABR version (${version})`); // TODO: ...
120
+ readLegacyBrushes(reader, version, samples, brushes, skip);
107
121
  }
108
122
  else if (version === 6 || version === 7 || version === 9 || version === 10) {
109
123
  const minorVersion = (0, psdReader_1.readInt16)(reader);
110
124
  if (minorVersion !== 1 && minorVersion !== 2)
111
125
  throw new Error('Unsupported ABR minor version');
112
- 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) {
113
128
  (0, psdReader_1.checkSignature)(reader, '8BIM');
114
129
  const type = (0, psdReader_1.readSignature)(reader);
115
- let size = (0, psdReader_1.readUint32)(reader);
116
- const end = reader.offset + size;
117
- switch (type) {
118
- case 'samp': {
119
- while (reader.offset < end) {
120
- let brushLength = (0, psdReader_1.readUint32)(reader);
121
- while (brushLength & 0b11)
122
- brushLength++; // pad to 4 byte alignment
123
- const brushEnd = reader.offset + brushLength;
124
- const id = (0, psdReader_1.readPascalString)(reader, 1);
125
- // v1 - Skip the Int16 bounds rectangle and the unknown Int16.
126
- // v2 - Skip the unknown bytes.
127
- (0, psdReader_1.skipBytes)(reader, minorVersion === 1 ? 10 : 264);
128
- const y = (0, psdReader_1.readInt32)(reader);
129
- const x = (0, psdReader_1.readInt32)(reader);
130
- const h = (0, psdReader_1.readInt32)(reader) - y;
131
- const w = (0, psdReader_1.readInt32)(reader) - x;
132
- if (w <= 0 || h <= 0)
133
- throw new Error('Invalid bounds');
134
- const bithDepth = (0, psdReader_1.readInt16)(reader);
135
- const compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
136
- const alpha = new Uint8Array(w * h);
137
- if (bithDepth === 8) {
138
- if (compression === 0) {
139
- alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
140
- }
141
- else if (compression === 1) {
142
- (0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
130
+ const size = (0, psdReader_1.readUint32)(reader);
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);
143
143
  }
144
- else {
145
- throw new Error('Invalid compression');
144
+ catch (e) {
145
+ skip(e, 'brush sample');
146
146
  }
147
+ reader.offset = brushEnd;
147
148
  }
148
- else if (bithDepth === 16) {
149
- if (compression === 0) {
150
- for (let i = 0; i < alpha.byteLength; i++) {
151
- alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
152
- }
153
- }
154
- else if (compression === 1) {
155
- 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;
156
158
  }
157
- else {
158
- throw new Error('Invalid compression');
159
+ catch (e) {
160
+ skip(e, `brush "${brush['Nm ']}"`);
159
161
  }
160
162
  }
161
- else {
162
- throw new Error('Invalid depth');
163
- }
164
- samples.push({ id, bounds: { x, y, w, h }, alpha });
165
- reader.offset = brushEnd;
163
+ break;
166
164
  }
167
- break;
168
- }
169
- case 'desc': {
170
- const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
171
- // console.log(require('util').inspect(desc, false, 99, true));
172
- // require('fs').writeFileSync('test.log', require('util').inspect(desc, false, 99, false), 'utf8');
173
- for (const brush of desc.Brsh) {
174
- const b = {
175
- name: brush['Nm '],
176
- shape: parseBrushShape(brush.Brsh),
177
- spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
178
- // TODO: brushGroup ???
179
- wetEdges: brush.Wtdg,
180
- noise: brush.Nose,
181
- // TODO: TxtC ??? smoothing / build-up ?
182
- // TODO: 'Rpt ' ???
183
- useBrushSize: brush.useBrushSize, // ???
184
- };
185
- if (brush.interpretation != null)
186
- b.interpretation = brush.interpretation;
187
- if (brush.protectTexture != null)
188
- b.protectTexture = brush.protectTexture;
189
- if (brush.useTipDynamics) {
190
- b.shapeDynamics = {
191
- tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
192
- sizeDynamics: parseDynamics(brush.szVr),
193
- angleDynamics: parseDynamics(brush.angleDynamics),
194
- roundnessDynamics: parseDynamics(brush.roundnessDynamics),
195
- flipX: brush.flipX,
196
- flipY: brush.flipY,
197
- brushProjection: brush.brushProjection,
198
- minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
199
- minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
200
- };
201
- }
202
- if (brush.useScatter) {
203
- b.scatter = {
204
- count: brush['Cnt '],
205
- bothAxes: brush.bothAxes,
206
- countDynamics: parseDynamics(brush.countDynamics),
207
- scatterDynamics: parseDynamics(brush.scatterDynamics),
208
- };
209
- }
210
- if (brush.useTexture && brush.Txtr) {
211
- b.texture = {
212
- id: brush.Txtr.Idnt,
213
- name: brush.Txtr['Nm '],
214
- blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
215
- depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
216
- depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
217
- depthDynamics: parseDynamics(brush.textureDepthDynamics),
218
- scale: (0, descriptor_1.parsePercent)(brush.textureScale),
219
- invert: brush.InvT,
220
- brightness: brush.textureBrightness,
221
- contrast: brush.textureContrast,
222
- textureEachTip: !!brush.TxtC,
223
- };
165
+ case 'patt': {
166
+ while (reader.offset + 4 <= end) {
167
+ const pattern = (0, psdReader_1.readPatternSafe)(reader);
168
+ if (pattern)
169
+ patterns.push(pattern);
224
170
  }
225
- const db = brush.dualBrush;
226
- if (db && db.useDualBrush) {
227
- b.dualBrush = {
228
- flip: db.Flip,
229
- shape: parseBrushShape(db.Brsh),
230
- blendMode: descriptor_1.BlnM.decode(db.BlnM),
231
- useScatter: db.useScatter,
232
- spacing: (0, descriptor_1.parsePercent)(db.Spcn),
233
- count: db['Cnt '],
234
- bothAxes: db.bothAxes,
235
- countDynamics: parseDynamics(db.countDynamics),
236
- scatterDynamics: parseDynamics(db.scatterDynamics),
237
- };
238
- }
239
- if (brush.useColorDynamics) {
240
- b.colorDynamics = {
241
- foregroundBackground: parseDynamics(brush.clVr),
242
- hue: (0, descriptor_1.parsePercent)(brush['H ']),
243
- saturation: (0, descriptor_1.parsePercent)(brush.Strt),
244
- brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
245
- purity: (0, descriptor_1.parsePercent)(brush.purity),
246
- perTip: brush.colorDynamicsPerTip,
247
- };
248
- }
249
- if (brush.usePaintDynamics) {
250
- b.transfer = {
251
- flowDynamics: parseDynamics(brush.prVr),
252
- opacityDynamics: parseDynamics(brush.opVr),
253
- wetnessDynamics: parseDynamics(brush.wtVr),
254
- mixDynamics: parseDynamics(brush.mxVr),
255
- };
256
- }
257
- if (brush.useBrushPose) {
258
- b.brushPose = {
259
- overrideAngle: brush.overridePoseAngle,
260
- overrideTiltX: brush.overridePoseTiltX,
261
- overrideTiltY: brush.overridePoseTiltY,
262
- overridePressure: brush.overridePosePressure,
263
- pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
264
- tiltX: brush.brushPoseTiltX,
265
- tiltY: brush.brushPoseTiltY,
266
- angle: brush.brushPoseAngle,
267
- };
268
- }
269
- const to = brush.toolOptions;
270
- if (to) {
271
- b.toolOptions = {
272
- type: toBrushType[to._classID] || 'brush',
273
- brushPreset: to.brushPreset,
274
- flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
275
- smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
276
- mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
277
- opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
278
- smoothing: !!to.smoothing,
279
- smoothingValue: to.smoothingValue || 0,
280
- smoothingRadiusMode: !!to.smoothingRadiusMode,
281
- smoothingCatchup: !!to.smoothingCatchup,
282
- smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
283
- smoothingZoomCompensation: !!to.smoothingZoomCompensation,
284
- pressureSmoothing: !!to.pressureSmoothing,
285
- usePressureOverridesSize: !!to.usePressureOverridesSize,
286
- usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
287
- useLegacy: !!to.useLegacy,
288
- };
289
- if (to.prVr)
290
- b.toolOptions.flowDynamics = parseDynamics(to.prVr);
291
- if (to.opVr)
292
- b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
293
- if (to.szVr)
294
- b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
295
- if ('wetness' in to)
296
- b.toolOptions.wetness = to.wetness;
297
- if ('dryness' in to)
298
- b.toolOptions.dryness = to.dryness;
299
- if ('mix' in to)
300
- b.toolOptions.mix = to.mix;
301
- if ('autoFill' in to)
302
- b.toolOptions.autoFill = to.autoFill;
303
- if ('autoClean' in to)
304
- b.toolOptions.autoClean = to.autoClean;
305
- if ('loadSolidColorOnly' in to)
306
- b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
307
- if ('sampleAllLayers' in to)
308
- b.toolOptions.sampleAllLayers = to.sampleAllLayers;
309
- if ('SmdF' in to)
310
- b.toolOptions.smudgeFingerPainting = to.SmdF;
311
- if ('SmdS' in to)
312
- b.toolOptions.smudgeSampleAllLayers = to.SmdS;
313
- if ('Prs ' in to)
314
- b.toolOptions.strength = to['Prs '];
315
- }
316
- brushes.push(b);
317
- }
318
- break;
319
- }
320
- case 'patt': {
321
- while (reader.offset < end) {
322
- patterns.push((0, psdReader_1.readPattern)(reader));
171
+ break;
323
172
  }
324
- reader.offset = end;
325
- break;
326
- }
327
- case 'phry': {
328
- // TODO: what is this ?
329
- const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
330
- // example:
331
- // hierarchy: [
332
- // {
333
- // 'Nm ': 'PRE_EXPORT ',
334
- // zuid: '965209f2-6f35-9a40-aa43-485684382172'
335
- // },
336
- // {},
337
- // ...
338
- // ]
339
- if (options.logMissingFeatures) {
340
- if ((_d = desc.hierarchy) === null || _d === void 0 ? void 0 : _d.length) {
341
- // console.log('unhandled phry section', desc);
342
- }
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;
343
178
  }
344
- break;
179
+ default:
180
+ // 'lPdc' (tool presets) and other unknown sections
181
+ options.logMissingFeatures && reader.log(`Unhandled brush section: ${type}`);
182
+ break;
345
183
  }
346
- default:
347
- throw new Error(`Invalid brush type: ${type}`);
348
184
  }
349
- // align to 4 bytes
350
- while (size % 4) {
351
- reader.offset++;
352
- size++;
185
+ catch (e) {
186
+ skip(e, `brush section ${type}`);
353
187
  }
188
+ // skip any unread data in the section and align to 4 bytes
189
+ reader.offset = end;
190
+ while (reader.offset % 4)
191
+ reader.offset++;
354
192
  }
355
193
  }
356
194
  else {
357
195
  throw new Error(`Unsupported ABR version (${version})`);
358
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
+ }
359
215
  return { samples, patterns, brushes };
360
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
+ }
361
495
  //# sourceMappingURL=abr.js.map