ag-psd 25.0.0 → 27.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 (58) hide show
  1. package/.v8-cache/v22.13.1-x64-00250a7c/4511bacf +0 -0
  2. package/.v8-cache/v22.13.1-x64-00250a7c/acc36e66 +0 -0
  3. package/.v8-cache/v22.13.1-x64-00250a7c/b3c2fab7 +0 -0
  4. package/.v8-cache/v22.13.1-x64-00250a7c/c314aece +0 -0
  5. package/.v8-cache/v22.13.1-x64-00250a7c/cfc49f4f +0 -0
  6. package/.v8-cache/v22.13.1-x64-00250a7c/d02dd6f7 +0 -0
  7. package/.v8-cache/v22.13.1-x64-00250a7c/e03e2acd +0 -0
  8. package/CHANGELOG.md +6 -0
  9. package/{TODO → TODO.md} +46 -0
  10. package/dist/additionalInfo.js +86 -54
  11. package/dist/additionalInfo.js.map +1 -1
  12. package/dist/bundle.js +683 -194
  13. package/dist/descriptor.js +4 -4
  14. package/dist/descriptor.js.map +1 -1
  15. package/dist/engineData2.d.ts +2 -1
  16. package/dist/engineData2.js +59 -3
  17. package/dist/engineData2.js.map +1 -1
  18. package/dist/helpers.d.ts +1 -0
  19. package/dist/helpers.js.map +1 -1
  20. package/dist/imageResources.js +39 -5
  21. package/dist/imageResources.js.map +1 -1
  22. package/dist/psd.d.ts +26 -0
  23. package/dist/psd.js.map +1 -1
  24. package/dist/psdReader.js +29 -31
  25. package/dist/psdReader.js.map +1 -1
  26. package/dist/psdWriter.js +79 -67
  27. package/dist/psdWriter.js.map +1 -1
  28. package/dist/text.d.ts +13 -2
  29. package/dist/text.js.map +1 -1
  30. package/dist-es/additionalInfo.js +86 -54
  31. package/dist-es/additionalInfo.js.map +1 -1
  32. package/dist-es/descriptor.js +4 -4
  33. package/dist-es/descriptor.js.map +1 -1
  34. package/dist-es/engineData2.d.ts +2 -1
  35. package/dist-es/engineData2.js +59 -3
  36. package/dist-es/engineData2.js.map +1 -1
  37. package/dist-es/helpers.d.ts +1 -0
  38. package/dist-es/helpers.js.map +1 -1
  39. package/dist-es/imageResources.js +41 -7
  40. package/dist-es/imageResources.js.map +1 -1
  41. package/dist-es/psd.d.ts +26 -0
  42. package/dist-es/psd.js.map +1 -1
  43. package/dist-es/psdReader.js +29 -31
  44. package/dist-es/psdReader.js.map +1 -1
  45. package/dist-es/psdWriter.js +79 -67
  46. package/dist-es/psdWriter.js.map +1 -1
  47. package/dist-es/text.d.ts +13 -2
  48. package/dist-es/text.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/additionalInfo.ts +91 -55
  51. package/src/descriptor.ts +5 -4
  52. package/src/engineData2.ts +62 -4
  53. package/src/helpers.ts +1 -0
  54. package/src/imageResources.ts +46 -20
  55. package/src/psd.ts +30 -0
  56. package/src/psdReader.ts +32 -34
  57. package/src/psdWriter.ts +75 -69
  58. package/src/text.ts +16 -2
package/src/psdReader.ts CHANGED
@@ -326,7 +326,7 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
326
326
  }
327
327
 
328
328
  if (left() >= 12) {
329
- readAdditionalLayerInfo(reader, psd, psd,);
329
+ readAdditionalLayerInfo(reader, psd, psd);
330
330
  } else {
331
331
  // opt.logMissingFeatures && console.log('skipping leftover bytes', left());
332
332
  skipBytes(reader, left());
@@ -443,8 +443,7 @@ function readLayerRecord(reader: PsdReader, psd: Psd) {
443
443
  skipBytes(reader, 1);
444
444
 
445
445
  readSection(reader, 1, left => {
446
- const mask = readLayerMaskData(reader);
447
- if (mask) layer.mask = mask;
446
+ readLayerMaskData(reader, layer);
448
447
 
449
448
  const blendingRanges = readLayerBlendingRanges(reader);
450
449
  if (blendingRanges) layer.blendingRanges = blendingRanges;
@@ -461,11 +460,13 @@ function readLayerRecord(reader: PsdReader, psd: Psd) {
461
460
  return { layer, channels };
462
461
  }
463
462
 
464
- function readLayerMaskData(reader: PsdReader) {
463
+ function readLayerMaskData(reader: PsdReader, layer: Layer) {
465
464
  return readSection<LayerMaskData | undefined>(reader, 1, left => {
466
465
  if (!left()) return undefined;
467
466
 
468
467
  const mask: LayerMaskData = {};
468
+ layer.mask = mask;
469
+
469
470
  mask.top = readInt32(reader);
470
471
  mask.left = readInt32(reader);
471
472
  mask.bottom = readInt32(reader);
@@ -477,6 +478,22 @@ function readLayerMaskData(reader: PsdReader) {
477
478
  mask.disabled = (flags & LayerMaskFlags.LayerMaskDisabled) !== 0;
478
479
  mask.fromVectorData = (flags & LayerMaskFlags.LayerMaskFromRenderingOtherData) !== 0;
479
480
 
481
+ if (left() >= 18) {
482
+ const realMask: LayerMaskData = {};
483
+ layer.realMask = realMask;
484
+
485
+ const realFlags = readUint8(reader);
486
+ realMask.positionRelativeToLayer = (realFlags & LayerMaskFlags.PositionRelativeToLayer) !== 0;
487
+ realMask.disabled = (realFlags & LayerMaskFlags.LayerMaskDisabled) !== 0;
488
+ realMask.fromVectorData = (realFlags & LayerMaskFlags.LayerMaskFromRenderingOtherData) !== 0;
489
+
490
+ realMask.defaultColor = readUint8(reader); // Real user mask background. 0 or 255.
491
+ realMask.top = readInt32(reader);
492
+ realMask.left = readInt32(reader);
493
+ realMask.bottom = readInt32(reader);
494
+ realMask.right = readInt32(reader);
495
+ }
496
+
480
497
  if (flags & LayerMaskFlags.MaskHasParametersAppliedToIt) {
481
498
  const params = readUint8(reader);
482
499
  if (params & MaskParams.UserMaskDensity) mask.userMaskDensity = readUint8(reader) / 0xff;
@@ -485,25 +502,7 @@ function readLayerMaskData(reader: PsdReader) {
485
502
  if (params & MaskParams.VectorMaskFeather) mask.vectorMaskFeather = readFloat64(reader);
486
503
  }
487
504
 
488
- if (left() > 2) {
489
- // TODO: handle these values, this is RealUserMask
490
- /*const realFlags = readUint8(reader);
491
- const realUserMaskBackground = readUint8(reader);
492
- const top2 = readInt32(reader);
493
- const left2 = readInt32(reader);
494
- const bottom2 = readInt32(reader);
495
- const right2 = readInt32(reader);
496
-
497
- // TEMP
498
- (mask as any)._real = { realFlags, realUserMaskBackground, top2, left2, bottom2, right2 };*/
499
-
500
- if (reader.logMissingFeatures) {
501
- reader.log('Unhandled extra real user mask params');
502
- }
503
- }
504
-
505
505
  skipBytes(reader, left());
506
- return mask;
507
506
  });
508
507
  }
509
508
 
@@ -572,13 +571,13 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
572
571
 
573
572
  if (compression > 3) throw new Error(`Invalid compression: ${compression}`);
574
573
 
575
- if (channel.id === ChannelID.UserMask) {
576
- const mask = layer.mask;
577
-
578
- if (!mask) throw new Error(`Missing layer mask data`);
574
+ if (channel.id === ChannelID.UserMask || channel.id === ChannelID.RealUserMask) {
575
+ const mask = channel.id === ChannelID.UserMask ? layer.mask : layer.realMask;
576
+ if (!mask) throw new Error(`Missing layer ${channel.id === ChannelID.UserMask ? 'mask' : 'real mask'} data`);
579
577
 
580
578
  const maskWidth = (mask.right || 0) - (mask.left || 0);
581
579
  const maskHeight = (mask.bottom || 0) - (mask.top || 0);
580
+ if (maskWidth < 0 || maskHeight < 0 || maskWidth > 30000 || maskHeight > 30000) throw new Error('Invalid mask size');
582
581
 
583
582
  if (maskWidth && maskHeight) {
584
583
  const maskData = createImageDataBitDepth(maskWidth, maskHeight, psd.bitsPerChannel ?? 8);
@@ -588,8 +587,13 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
588
587
  readData(reader, channel.length, maskData, compression, maskWidth, maskHeight, psd.bitsPerChannel ?? 8, 0, reader.large, 4);
589
588
 
590
589
  if (RAW_IMAGE_DATA) {
591
- (layer as any).maskDataRawCompression = compression;
592
- (layer as any).maskDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
590
+ if (channel.id === ChannelID.UserMask) {
591
+ (layer as any).maskDataRawCompression = compression;
592
+ (layer as any).maskDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
593
+ } else {
594
+ (layer as any).realMaskDataRawCompression = compression;
595
+ (layer as any).realMaskDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
596
+ }
593
597
  }
594
598
 
595
599
  setupGrayscale(maskData);
@@ -600,12 +604,6 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
600
604
  mask.canvas = imageDataToCanvas(maskData);
601
605
  }
602
606
  }
603
- } else if (channel.id === ChannelID.RealUserMask) {
604
- if (reader.logMissingFeatures) {
605
- reader.log(`RealUserMask not supported`);
606
- }
607
-
608
- reader.offset = start + channel.length;
609
607
  } else {
610
608
  const offset = offsetForChannel(channel.id, cmyk);
611
609
  let targetData = imageData;
package/src/psdWriter.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Psd, Layer, LayerAdditionalInfo, ColorMode, SectionDividerType, WriteOptions, Color, GlobalLayerMaskInfo, PixelData } from './psd';
1
+ import { Psd, Layer, LayerAdditionalInfo, ColorMode, SectionDividerType, WriteOptions, Color, GlobalLayerMaskInfo, PixelData, LayerMaskData } from './psd';
2
2
  import { hasAlpha, createCanvas, writeDataRLE, LayerChannelData, ChannelData, offsetForChannel, createImageData, fromBlendMode, ChannelID, Compression, clamp, LayerMaskFlags, MaskParams, ColorSpace, Bounds, largeAdditionalInfoKeys, RAW_IMAGE_DATA, writeDataZipWithoutPrediction, imageDataToCanvas } from './helpers';
3
3
  import { ExtendedWriteOptions, infoHandlers } from './additionalInfo';
4
4
  import { resourceHandlers } from './imageResources';
@@ -354,7 +354,7 @@ function writeLayerInfo(writer: PsdWriter, psd: Psd, globalAlpha: boolean, optio
354
354
  let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
355
355
  if (layer.transparencyProtected) flags |= 0x01;
356
356
  if (layer.hidden) flags |= 0x02;
357
- if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== SectionDividerType.Other)) {
357
+ if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== SectionDividerType.Other) || layer.adjustment) {
358
358
  flags |= 0x10; // pixel data irrelevant to appearance of document
359
359
  }
360
360
  if (layer.effectsOpen) flags |= 0x20;
@@ -382,42 +382,54 @@ function writeLayerInfo(writer: PsdWriter, psd: Psd, globalAlpha: boolean, optio
382
382
  }, true, options.psb);
383
383
  }
384
384
 
385
- function writeLayerMaskData(writer: PsdWriter, { mask }: Layer, layerData: LayerChannelData) {
385
+ function writeLayerMaskData(writer: PsdWriter, { mask, realMask }: Layer, layerData: LayerChannelData) {
386
386
  writeSection(writer, 1, () => {
387
- if (!mask) return;
387
+ if (!mask && !realMask) return;
388
+
389
+ let params = 0, flags = 0, realFlags = 0;
390
+
391
+ if (mask) {
392
+ if (mask.userMaskDensity !== undefined) params |= MaskParams.UserMaskDensity;
393
+ if (mask.userMaskFeather !== undefined) params |= MaskParams.UserMaskFeather;
394
+ if (mask.vectorMaskDensity !== undefined) params |= MaskParams.VectorMaskDensity;
395
+ if (mask.vectorMaskFeather !== undefined) params |= MaskParams.VectorMaskFeather;
396
+
397
+ if (mask.disabled) flags |= LayerMaskFlags.LayerMaskDisabled;
398
+ if (mask.positionRelativeToLayer) flags |= LayerMaskFlags.PositionRelativeToLayer;
399
+ if (mask.fromVectorData) flags |= LayerMaskFlags.LayerMaskFromRenderingOtherData;
400
+ if (params) flags |= LayerMaskFlags.MaskHasParametersAppliedToIt;
401
+ }
388
402
 
389
403
  const m = layerData.mask || {} as Partial<Bounds>;
390
404
  writeInt32(writer, m.top || 0);
391
405
  writeInt32(writer, m.left || 0);
392
406
  writeInt32(writer, m.bottom || 0);
393
407
  writeInt32(writer, m.right || 0);
394
- writeUint8(writer, mask.defaultColor || 0);
395
-
396
- let params = 0;
397
- if (mask.userMaskDensity !== undefined) params |= MaskParams.UserMaskDensity;
398
- if (mask.userMaskFeather !== undefined) params |= MaskParams.UserMaskFeather;
399
- if (mask.vectorMaskDensity !== undefined) params |= MaskParams.VectorMaskDensity;
400
- if (mask.vectorMaskFeather !== undefined) params |= MaskParams.VectorMaskFeather;
401
-
402
- let flags = 0;
403
- if (mask.disabled) flags |= LayerMaskFlags.LayerMaskDisabled;
404
- if (mask.positionRelativeToLayer) flags |= LayerMaskFlags.PositionRelativeToLayer;
405
- if (mask.fromVectorData) flags |= LayerMaskFlags.LayerMaskFromRenderingOtherData;
406
- if (params) flags |= LayerMaskFlags.MaskHasParametersAppliedToIt;
407
-
408
+ writeUint8(writer, mask && mask.defaultColor || 0);
408
409
  writeUint8(writer, flags);
409
410
 
410
- if (params) {
411
- writeUint8(writer, params);
411
+ if (realMask) {
412
+ if (realMask.disabled) realFlags |= LayerMaskFlags.LayerMaskDisabled;
413
+ if (realMask.positionRelativeToLayer) realFlags |= LayerMaskFlags.PositionRelativeToLayer;
414
+ if (realMask.fromVectorData) realFlags |= LayerMaskFlags.LayerMaskFromRenderingOtherData;
415
+
416
+ const r = layerData.realMask || {} as Partial<Bounds>;
417
+ writeUint8(writer, realFlags);
418
+ writeUint8(writer, realMask.defaultColor || 0);
419
+ writeInt32(writer, r.top || 0);
420
+ writeInt32(writer, r.left || 0);
421
+ writeInt32(writer, r.bottom || 0);
422
+ writeInt32(writer, r.right || 0);
423
+ }
412
424
 
425
+ if (params && mask) {
426
+ writeUint8(writer, params);
413
427
  if (mask.userMaskDensity !== undefined) writeUint8(writer, Math.round(mask.userMaskDensity * 0xff));
414
428
  if (mask.userMaskFeather !== undefined) writeFloat64(writer, mask.userMaskFeather);
415
429
  if (mask.vectorMaskDensity !== undefined) writeUint8(writer, Math.round(mask.vectorMaskDensity * 0xff));
416
430
  if (mask.vectorMaskFeather !== undefined) writeFloat64(writer, mask.vectorMaskFeather);
417
431
  }
418
432
 
419
- // TODO: handle rest of the fields
420
-
421
433
  writeZeros(writer, 2);
422
434
  });
423
435
  }
@@ -485,8 +497,8 @@ function writeAdditionalLayerInfo(writer: PsdWriter, target: LayerAdditionalInfo
485
497
  function addChildren(layers: Layer[], children: Layer[] | undefined) {
486
498
  if (!children) return;
487
499
 
488
- // const layerIds = [];
489
- // const timestamps = []
500
+ // const layerIds: number[] = [2];
501
+ // const timestamps: number[] = [1740120767.0230637];
490
502
 
491
503
  for (const c of children) {
492
504
  if (c.children && c.canvas) throw new Error(`Invalid layer, cannot have both 'canvas' and 'children' properties`);
@@ -498,6 +510,7 @@ function addChildren(layers: Layer[], children: Layer[] | undefined) {
498
510
  sectionDivider: {
499
511
  type: SectionDividerType.BoundingSectionDivider,
500
512
  },
513
+ // blendingRanges: children[0].blendingRanges,
501
514
  // nameSource: 'lset',
502
515
  // id: layerIds.shift(),
503
516
  // protected: {
@@ -505,12 +518,9 @@ function addChildren(layers: Layer[], children: Layer[] | undefined) {
505
518
  // composite: false,
506
519
  // position: false,
507
520
  // },
508
- // layerColor: 'none',
521
+ // layerColor: 'red',
509
522
  // timestamp: timestamps.shift(),
510
- // referencePoint: {
511
- // x: 0,
512
- // y: 0,
513
- // },
523
+ // referencePoint: { x: 0, y: 0 },
514
524
  });
515
525
  addChildren(layers, c.children);
516
526
  layers.push({
@@ -581,54 +591,50 @@ function createThumbnail(psd: Psd) {
581
591
  return canvas;
582
592
  }
583
593
 
584
- function getChannels(
585
- tempBuffer: Uint8Array, layer: Layer, background: boolean, options: WriteOptions
586
- ): LayerChannelData {
587
- const layerData = getLayerChannels(tempBuffer, layer, background, options);
588
- const mask = layer.mask;
589
-
590
- if (mask) {
591
- let top = (mask.top as any) | 0;
592
- let left = (mask.left as any) | 0;
593
- let right = (mask.right as any) | 0;
594
- let bottom = (mask.bottom as any) | 0;
595
- let { width, height } = getLayerDimentions(mask);
596
- let imageData = mask.imageData;
597
-
598
- if (!imageData && mask.canvas && width && height) {
599
- imageData = mask.canvas.getContext('2d')!.getImageData(0, 0, width, height);
600
- }
594
+ function getMaskChannels(tempBuffer: Uint8Array, layerData: LayerChannelData, layer: Layer, mask: LayerMaskData, options: WriteOptions, realMask: boolean) {
595
+ let top = (mask.top as any) | 0;
596
+ let left = (mask.left as any) | 0;
597
+ let right = (mask.right as any) | 0;
598
+ let bottom = (mask.bottom as any) | 0;
599
+ let { width, height } = getLayerDimentions(mask);
600
+ let imageData = mask.imageData;
601
601
 
602
- if (width && height && imageData) {
603
- right = left + width;
604
- bottom = top + height;
602
+ if (!imageData && mask.canvas && width && height) {
603
+ imageData = mask.canvas.getContext('2d')!.getImageData(0, 0, width, height);
604
+ }
605
605
 
606
- if (imageData.width !== width || imageData.height !== height) {
607
- throw new Error('Invalid imageData dimentions');
608
- }
606
+ if (width && height && imageData) {
607
+ right = left + width;
608
+ bottom = top + height;
609
609
 
610
- let buffer: Uint8Array;
611
- let compression: Compression;
612
-
613
- if (RAW_IMAGE_DATA && (layer as any).maskDataRaw) {
614
- // console.log('written raw layer image data');
615
- buffer = (layer as any).maskDataRaw;
616
- compression = (layer as any).maskDataRawCompression;
617
- } else if (options.compress) {
618
- buffer = writeDataZipWithoutPrediction(imageData, [0]);
619
- compression = Compression.ZipWithoutPrediction;
620
- } else {
621
- buffer = writeDataRLE(tempBuffer, imageData, [0], !!options.psb)!;
622
- compression = Compression.RleCompressed;
623
- }
610
+ if (imageData.width !== width || imageData.height !== height) {
611
+ throw new Error('Invalid imageData dimentions');
612
+ }
613
+
614
+ let buffer: Uint8Array;
615
+ let compression: Compression;
624
616
 
625
- layerData.mask = { top, left, right, bottom };
626
- layerData.channels.push({ channelId: ChannelID.UserMask, compression, buffer, length: 2 + buffer.length });
617
+ if (RAW_IMAGE_DATA && (layer as any)[realMask ? 'realMaskDataRaw' : 'maskDataRaw']) {
618
+ buffer = (layer as any)[realMask ? 'realMaskDataRaw' : 'maskDataRaw'];
619
+ compression = (layer as any)[realMask ? 'realMaskDataRawCompression' : 'maskDataRawCompression'];
620
+ } else if (options.compress) {
621
+ buffer = writeDataZipWithoutPrediction(imageData, [0]);
622
+ compression = Compression.ZipWithoutPrediction;
627
623
  } else {
628
- layerData.mask = { top: 0, left: 0, right: 0, bottom: 0 };
624
+ buffer = writeDataRLE(tempBuffer, imageData, [0], !!options.psb)!;
625
+ compression = Compression.RleCompressed;
629
626
  }
627
+
628
+ layerData.channels.push({ channelId: realMask ? ChannelID.RealUserMask : ChannelID.UserMask, compression, buffer, length: 2 + buffer.length });
630
629
  }
631
630
 
631
+ layerData[realMask ? 'realMask' : 'mask'] = { top, left, right, bottom };
632
+ }
633
+
634
+ function getChannels(tempBuffer: Uint8Array, layer: Layer, background: boolean, options: WriteOptions): LayerChannelData {
635
+ const layerData = getLayerChannels(tempBuffer, layer, background, options);
636
+ if (layer.mask) getMaskChannels(tempBuffer, layerData, layer, layer.mask, options, false);
637
+ if (layer.realMask) getMaskChannels(tempBuffer, layerData, layer, layer.realMask, options, true);
632
638
  return layerData;
633
639
  }
634
640
 
package/src/text.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { TextStyle, LayerTextData, ParagraphStyle, Font, AntiAlias, TextGridInfo, Justification, Color } from './psd';
1
+ import type { TextStyle, LayerTextData, ParagraphStyle, Font, AntiAlias, TextGridInfo, Justification, Color, TextPath } from './psd';
2
2
 
3
3
  interface Adjustments {
4
4
  Axis: number[];
@@ -120,7 +120,7 @@ interface PhotoshopNode {
120
120
  };
121
121
  }
122
122
 
123
- interface EngineData {
123
+ export interface EngineData {
124
124
  EngineDict: {
125
125
  Editor: { Text: string; };
126
126
  ParagraphRun: {
@@ -165,6 +165,20 @@ interface EngineData {
165
165
  DocumentResources: ResourceDict;
166
166
  }
167
167
 
168
+ export interface GlobalEngineData {
169
+ ResourceDict: {
170
+ FontSet: any[]; // TODO
171
+ StyleSheetSet: any[]; // TODO
172
+ ParagraphSheetSet: any[]; // TODO
173
+ TextFrameSet?: {
174
+ path: TextPath;
175
+ }[];
176
+ };
177
+ EngineDict: {
178
+ // TODO
179
+ };
180
+ }
181
+
168
182
  const defaultFont: Font = {
169
183
  name: 'MyriadPro-Regular',
170
184
  script: 0,