ag-psd 18.0.0 → 19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ag-psd",
3
- "version": "18.0.0",
3
+ "version": "19.0.0",
4
4
  "description": "Library for reading and writing PSD files",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist-es/index.js",
package/src/abr.ts CHANGED
@@ -116,8 +116,12 @@ export interface Brush {
116
116
  interpretation?: boolean; // ?
117
117
  useBrushSize: boolean; // ?
118
118
  toolOptions?: {
119
+ type: 'brush' | 'mixer brush' | 'smudge brush';
119
120
  brushPreset: boolean;
120
121
  flow: number; // 0-100
122
+ wetness?: number; // 0-100
123
+ dryness?: number; // 0-100
124
+ mix?: number; // 0-100
121
125
  smooth: number; // ?
122
126
  mode: BlendMode;
123
127
  opacity: number; // 0-100
@@ -131,9 +135,16 @@ export interface Brush {
131
135
  usePressureOverridesSize: boolean;
132
136
  usePressureOverridesOpacity: boolean;
133
137
  useLegacy: boolean;
138
+ autoFill?: boolean;
139
+ autoClean?: boolean;
140
+ loadSolidColorOnly?: boolean;
141
+ sampleAllLayers?: boolean;
134
142
  flowDynamics?: BrushDynamics;
135
143
  opacityDynamics?: BrushDynamics;
136
144
  sizeDynamics?: BrushDynamics;
145
+ smudgeFingerPainting?: boolean;
146
+ smudgeSampleAllLayers?: boolean;
147
+ strength?: number; // 0-100
137
148
  };
138
149
  }
139
150
 
@@ -241,8 +252,12 @@ interface DescDescriptor {
241
252
  brushPoseTiltY?: number;
242
253
  brushPoseAngle?: number;
243
254
  toolOptions?: {
255
+ _classID: string;
244
256
  brushPreset: boolean;
245
257
  flow?: number;
258
+ wetness?: number;
259
+ dryness?: number;
260
+ mix?: number;
246
261
  Smoo?: number;
247
262
  'Md ': string;
248
263
  Opct?: number;
@@ -256,16 +271,30 @@ interface DescDescriptor {
256
271
  usePressureOverridesSize?: boolean;
257
272
  usePressureOverridesOpacity?: boolean;
258
273
  useLegacy: boolean;
259
- 'Prs '?: number; // TODO: ???
274
+ autoFill?: boolean;
275
+ autoClean?: boolean;
276
+ loadSolidColorOnly?: boolean;
277
+ sampleAllLayers?: boolean;
278
+ 'Prs '?: number;
260
279
  MgcE?: boolean; // TODO: ???
261
280
  ErsB?: number; // TODO: ???
262
281
  prVr?: DynamicsDescriptor;
263
282
  opVr?: DynamicsDescriptor;
264
283
  szVr?: DynamicsDescriptor;
284
+ SmdF?: boolean;
285
+ SmdS?: boolean;
265
286
  };
266
287
  }[];
267
288
  }
268
289
 
290
+ const toBrushType: { [key: string]: 'brush' | 'mixer brush' | 'smudge brush'; } = {
291
+ _: 'brush',
292
+ MixB: 'mixer brush',
293
+ SmTl: 'smudge brush',
294
+ // PbTl
295
+ // ErTl
296
+ };
297
+
269
298
  function parseDynamics(desc: DynamicsDescriptor): BrushDynamics {
270
299
  return {
271
300
  control: dynamicsControl[desc.bVTy] as any,
@@ -363,7 +392,7 @@ export function readAbr(buffer: ArrayBufferView, options: { logMissingFeatures?:
363
392
  break;
364
393
  }
365
394
  case 'desc': {
366
- const desc: DescDescriptor = readVersionAndDescriptor(reader);
395
+ const desc: DescDescriptor = readVersionAndDescriptor(reader, true);
367
396
  // console.log(require('util').inspect(desc, false, 99, true));
368
397
 
369
398
  for (const brush of desc.Brsh) {
@@ -471,6 +500,7 @@ export function readAbr(buffer: ArrayBufferView, options: { logMissingFeatures?:
471
500
  const to = brush.toolOptions;
472
501
  if (to) {
473
502
  b.toolOptions = {
503
+ type: toBrushType[to._classID] || 'brush',
474
504
  brushPreset: to.brushPreset,
475
505
  flow: to.flow ?? 100,
476
506
  smooth: to.Smoo ?? 0,
@@ -488,17 +518,21 @@ export function readAbr(buffer: ArrayBufferView, options: { logMissingFeatures?:
488
518
  useLegacy: !!to.useLegacy,
489
519
  };
490
520
 
491
- if (to.prVr) {
492
- b.toolOptions.flowDynamics = parseDynamics(to.prVr);
493
- }
494
-
495
- if (to.opVr) {
496
- b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
497
- }
498
-
499
- if (to.szVr) {
500
- b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
501
- }
521
+ if (to.prVr) b.toolOptions.flowDynamics = parseDynamics(to.prVr);
522
+ if (to.opVr) b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
523
+ if (to.szVr) b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
524
+ if ('wetness' in to) b.toolOptions.wetness = to.wetness;
525
+ if ('dryness' in to) b.toolOptions.dryness = to.dryness;
526
+ if ('mix' in to) b.toolOptions.mix = to.mix;
527
+ if ('autoFill' in to) b.toolOptions.autoFill = to.autoFill;
528
+ if ('autoClean' in to) b.toolOptions.autoClean = to.autoClean;
529
+ if ('loadSolidColorOnly' in to) b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
530
+ if ('sampleAllLayers' in to) b.toolOptions.sampleAllLayers = to.sampleAllLayers;
531
+ if ('SmdF' in to) b.toolOptions.smudgeFingerPainting = to.SmdF;
532
+ if ('SmdS' in to) b.toolOptions.smudgeSampleAllLayers = to.SmdS;
533
+ if ('Prs ' in to) b.toolOptions.strength = to['Prs '];
534
+ if ('SmdF' in to) b.toolOptions.smudgeFingerPainting = to.SmdF;
535
+ if ('SmdS' in to) b.toolOptions.smudgeSampleAllLayers = to.SmdS;
502
536
  }
503
537
 
504
538
  brushes.push(b);
@@ -273,7 +273,7 @@ export function readVectorMask(reader: PsdReader, vectorMask: LayerVectorMask, w
273
273
  open: selector === 3,
274
274
  operation: boolOp === -1 ? 'combine' : booleanOperations[boolOp],
275
275
  knots: [],
276
- fillRule: flags & 2 ? 'non-zero' : 'even-odd',
276
+ fillRule: flags === 2 ? 'non-zero' : 'even-odd',
277
277
  };
278
278
  paths.push(path);
279
279
  break;
@@ -364,7 +364,7 @@ addHandler(
364
364
  writeUint16(writer, path.open ? 3 : 0);
365
365
  writeUint16(writer, path.knots.length);
366
366
  writeUint16(writer, Math.abs(booleanOperations.indexOf(path.operation))); // default to 1 if not found
367
- writeUint16(writer, 1 | (path.fillRule === 'non-zero' ? 2 : 0));
367
+ writeUint16(writer, path.fillRule === 'non-zero' ? 2 : 1);
368
368
  writeZeros(writer, 18); // TODO: these are sometimes non-zero
369
369
 
370
370
  const linkedKnot = path.open ? 4 : 1;
package/src/descriptor.ts CHANGED
@@ -350,11 +350,9 @@ function writeAsciiStringOrClassId(writer: PsdWriter, value: string) {
350
350
  }
351
351
  }
352
352
 
353
- export function readDescriptorStructure(reader: PsdReader) {
354
- // const struct =
355
- readClassStructure(reader);
356
- // const object: any = { _name: struct.name, _classID: struct.classID };
357
- const object: any = {};
353
+ export function readDescriptorStructure(reader: PsdReader, includeClass: boolean) {
354
+ const struct = readClassStructure(reader);
355
+ const object: any = includeClass ? { _name: struct.name, _classID: struct.classID } : {};
358
356
  // console.log('>> ', struct);
359
357
  const itemsCount = readUint32(reader);
360
358
 
@@ -362,7 +360,7 @@ export function readDescriptorStructure(reader: PsdReader) {
362
360
  const key = readAsciiStringOrClassId(reader);
363
361
  const type = readSignature(reader);
364
362
  // console.log(`> '${key}' '${type}'`);
365
- const data = readOSType(reader, type);
363
+ const data = readOSType(reader, type, includeClass);
366
364
  // if (!getTypeByKey(key, data)) console.log(`> '${key}' '${type}'`, data);
367
365
  object[key] = data;
368
366
  }
@@ -463,13 +461,13 @@ export function writeDescriptorStructure(writer: PsdWriter, name: string, classI
463
461
  }
464
462
  }
465
463
 
466
- function readOSType(reader: PsdReader, type: string) {
464
+ function readOSType(reader: PsdReader, type: string, includeClass: boolean) {
467
465
  switch (type) {
468
466
  case 'obj ': // Reference
469
467
  return readReferenceStructure(reader);
470
468
  case 'Objc': // Descriptor
471
469
  case 'GlbO': // GlobalObject same as Descriptor
472
- return readDescriptorStructure(reader);
470
+ return readDescriptorStructure(reader, includeClass);
473
471
  case 'VlLs': { // List
474
472
  const length = readInt32(reader);
475
473
  const items: any[] = [];
@@ -477,7 +475,7 @@ function readOSType(reader: PsdReader, type: string) {
477
475
  for (let i = 0; i < length; i++) {
478
476
  const type = readSignature(reader);
479
477
  // console.log(' >', type);
480
- items.push(readOSType(reader, type));
478
+ items.push(readOSType(reader, type, includeClass));
481
479
  }
482
480
 
483
481
  return items;
@@ -770,10 +768,10 @@ function writeClassStructure(writer: PsdWriter, name: string, classID: string) {
770
768
  writeAsciiStringOrClassId(writer, classID);
771
769
  }
772
770
 
773
- export function readVersionAndDescriptor(reader: PsdReader) {
771
+ export function readVersionAndDescriptor(reader: PsdReader, includeClass = false) {
774
772
  const version = readUint32(reader);
775
773
  if (version !== 16) throw new Error(`Invalid descriptor version: ${version}`);
776
- const desc = readDescriptorStructure(reader);
774
+ const desc = readDescriptorStructure(reader, includeClass);
777
775
  // console.log(require('util').inspect(desc, false, 99, true));
778
776
  return desc;
779
777
  }
package/src/psdWriter.ts CHANGED
@@ -177,7 +177,7 @@ export function writeSection(writer: PsdWriter, round: number, func: () => void,
177
177
  let length = writer.offset - offset - 4;
178
178
  let len = length;
179
179
 
180
- while ((len % round) !== 0) {
180
+ while ((writer.offset % round) !== 0) {
181
181
  writeUint8(writer, 0);
182
182
  len++;
183
183
  }
@@ -356,11 +356,11 @@ function writeLayerMaskData(writer: PsdWriter, { mask }: Layer, layerData: Layer
356
356
  if (!mask) return;
357
357
 
358
358
  const m = layerData.mask || {} as Partial<Bounds>;
359
- writeInt32(writer, m.top!);
360
- writeInt32(writer, m.left!);
361
- writeInt32(writer, m.bottom!);
362
- writeInt32(writer, m.right!);
363
- writeUint8(writer, mask.defaultColor!);
359
+ writeInt32(writer, m.top || 0);
360
+ writeInt32(writer, m.left || 0);
361
+ writeInt32(writer, m.bottom || 0);
362
+ writeInt32(writer, m.right || 0);
363
+ writeUint8(writer, mask.defaultColor || 0);
364
364
 
365
365
  let params = 0;
366
366
  if (mask.userMaskDensity !== undefined) params |= MaskParams.UserMaskDensity;
@@ -430,17 +430,16 @@ function writeAdditionalLayerInfo(writer: PsdWriter, target: LayerAdditionalInfo
430
430
 
431
431
  if (handler.has(target)) {
432
432
  const large = options.psb && largeAdditionalInfoKeys.indexOf(key) !== -1;
433
-
434
- writeSignature(writer, large ? '8B64' : '8BIM');
435
- writeSignature(writer, key);
436
-
433
+ const writeTotalLength = key !== 'Txt2' && key !== 'cinf' && key !== 'extn';
437
434
  const fourBytes = key === 'Txt2' || key === 'luni' || key === 'vmsk' || key === 'artb' || key === 'artd' ||
438
435
  key === 'vogk' || key === 'SoLd' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
439
436
  key === 'lmfx' || key === 'lrFX' || key === 'cinf' || key === 'PlLd' || key === 'Anno';
440
437
 
438
+ writeSignature(writer, large ? '8B64' : '8BIM');
439
+ writeSignature(writer, key);
441
440
  writeSection(writer, fourBytes ? 4 : 2, () => {
442
441
  handler.write(writer, target, psd, options);
443
- }, key !== 'Txt2' && key !== 'cinf' && key !== 'extn', large);
442
+ }, writeTotalLength, large);
444
443
  }
445
444
  }
446
445
  }
@@ -581,7 +580,6 @@ function getChannels(
581
580
  layerData.channels.push({ channelId: ChannelID.UserMask, compression, buffer, length: 2 + buffer.length });
582
581
  } else {
583
582
  layerData.mask = { top: 0, left: 0, right: 0, bottom: 0 };
584
- layerData.channels.push({ channelId: ChannelID.UserMask, compression: Compression.RawData, buffer: new Uint8Array(0), length: 0 });
585
583
  }
586
584
  }
587
585