ag-psd 22.0.2 → 23.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.
@@ -3603,134 +3603,187 @@ interface FileOpenDescriptor {
3603
3603
  compInfo: { compID: number; originalCompID: number; };
3604
3604
  }
3605
3605
 
3606
- addHandler(
3607
- 'lnk2',
3608
- (target: any) => !!(target as Psd).linkedFiles && (target as Psd).linkedFiles!.length > 0,
3609
- (reader, target, left) => {
3610
- const psd = target as Psd;
3611
- psd.linkedFiles = psd.linkedFiles || [];
3612
-
3613
- while (left() > 8) {
3614
- let size = readLength64(reader); // size
3615
- const startOffset = reader.offset;
3616
- const type = readSignature(reader) as 'liFD' | 'liFE' | 'liFA';
3617
- // liFD - linked file data
3618
- // liFE - linked file external
3619
- // liFA - linked file alias
3620
- const version = readInt32(reader);
3621
- const id = readPascalString(reader, 1);
3622
- const name = readUnicodeString(reader);
3623
-
3624
- const fileType = readSignature(reader).trim(); // ' ' if empty
3625
- const fileCreator = readSignature(reader).trim(); // ' ' or '\0\0\0\0' if empty
3626
- const dataSize = readLength64(reader);
3627
- const hasFileOpenDescriptor = readUint8(reader);
3628
- const fileOpenDescriptor = hasFileOpenDescriptor ? readVersionAndDescriptor(reader) as FileOpenDescriptor : undefined;
3629
- const linkedFileDescriptor = type === 'liFE' ? readVersionAndDescriptor(reader) : undefined;
3630
- const file: LinkedFile = { id, name };
3631
-
3632
- if (fileType) file.type = fileType;
3633
- if (fileCreator) file.creator = fileCreator;
3634
-
3635
- if (fileOpenDescriptor) {
3636
- file.descriptor = {
3637
- compInfo: {
3638
- compID: fileOpenDescriptor.compInfo.compID,
3639
- originalCompID: fileOpenDescriptor.compInfo.originalCompID,
3640
- }
3641
- };
3642
- }
3606
+ interface LinkedFileDescriptor {
3607
+ descVersion: 2;
3608
+ 'Nm ': string;
3609
+ fullPath: string;
3610
+ originalPath: string;
3611
+ relPath: string;
3612
+ }
3613
+
3614
+ function createLnkHandler(tag: string) {
3615
+ addHandler(
3616
+ tag,
3617
+ (target: any) => {
3618
+ const psd = target as Psd;
3619
+ if (!psd.linkedFiles || !psd.linkedFiles.length) return false;
3620
+ if (tag === 'lnkE' && !psd.linkedFiles.some(f => f.linkedFile)) return false;
3621
+ return true;
3622
+ },
3623
+ (reader, target, left, _psd) => {
3624
+ const psd = target as Psd;
3625
+ psd.linkedFiles = psd.linkedFiles || [];
3626
+
3627
+ while (left() > 8) {
3628
+ let size = readLength64(reader);
3629
+ const startOffset = reader.offset;
3630
+ const type = readSignature(reader) as 'liFD' | 'liFE' | 'liFA';
3631
+ // liFD - linked file data
3632
+ // liFE - linked file external
3633
+ // liFA - linked file alias
3634
+ const version = readInt32(reader);
3635
+ const id = readPascalString(reader, 1);
3636
+ const name = readUnicodeString(reader);
3637
+
3638
+ const fileType = readSignature(reader).trim(); // ' ' if empty
3639
+ const fileCreator = readSignature(reader).trim(); // ' ' or '\0\0\0\0' if empty
3640
+ const dataSize = readLength64(reader);
3641
+ const hasFileOpenDescriptor = readUint8(reader);
3642
+ const fileOpenDescriptor = hasFileOpenDescriptor ? readVersionAndDescriptor(reader) as FileOpenDescriptor : undefined;
3643
+ const linkedFileDescriptor = type === 'liFE' ? readVersionAndDescriptor(reader) as LinkedFileDescriptor : undefined;
3644
+ const file: LinkedFile = { id, name };
3645
+
3646
+ if (fileType) file.type = fileType;
3647
+ if (fileCreator) file.creator = fileCreator;
3648
+
3649
+ if (fileOpenDescriptor) {
3650
+ file.descriptor = {
3651
+ compInfo: {
3652
+ compID: fileOpenDescriptor.compInfo.compID,
3653
+ originalCompID: fileOpenDescriptor.compInfo.originalCompID,
3654
+ }
3655
+ };
3656
+ }
3643
3657
 
3644
- if (type === 'liFE' && version > 3) {
3645
- const year = readInt32(reader);
3646
- const month = readUint8(reader);
3647
- const day = readUint8(reader);
3648
- const hour = readUint8(reader);
3649
- const minute = readUint8(reader);
3650
- const seconds = readFloat64(reader);
3651
- const wholeSeconds = Math.floor(seconds);
3652
- const ms = (seconds - wholeSeconds) * 1000;
3653
- file.time = (new Date(year, month, day, hour, minute, wholeSeconds, ms)).toISOString();
3658
+ if (type === 'liFE' && version > 3) {
3659
+ const year = readInt32(reader);
3660
+ const month = readUint8(reader);
3661
+ const day = readUint8(reader);
3662
+ const hour = readUint8(reader);
3663
+ const minute = readUint8(reader);
3664
+ const seconds = readFloat64(reader);
3665
+ const wholeSeconds = Math.floor(seconds);
3666
+ const ms = (seconds - wholeSeconds) * 1000;
3667
+ file.time = (new Date(Date.UTC(year, month, day, hour, minute, wholeSeconds, ms))).toISOString();
3668
+ }
3669
+
3670
+ const fileSize = type === 'liFE' ? readLength64(reader) : 0;
3671
+
3672
+ if (type === 'liFA') skipBytes(reader, 8);
3673
+ if (type === 'liFD') file.data = readBytes(reader, dataSize); // seems to be a typo in docs
3674
+ if (version >= 5) file.childDocumentID = readUnicodeString(reader);
3675
+ if (version >= 6) file.assetModTime = readFloat64(reader);
3676
+ if (version >= 7) file.assetLockedState = readUint8(reader);
3677
+ if (type === 'liFE' && version === 2) file.data = readBytes(reader, fileSize);
3678
+
3679
+ if (reader.skipLinkedFilesData) file.data = undefined;
3680
+
3681
+ if (tag === 'lnkE') {
3682
+ file.linkedFile = {
3683
+ fileSize,
3684
+ name: linkedFileDescriptor?.['Nm '] || '',
3685
+ fullPath: linkedFileDescriptor?.fullPath || '',
3686
+ originalPath: linkedFileDescriptor?.originalPath || '',
3687
+ relativePath: linkedFileDescriptor?.relPath || '',
3688
+ };
3689
+ }
3690
+
3691
+ psd.linkedFiles.push(file);
3692
+
3693
+ while (size % 4) size++;
3694
+ reader.offset = startOffset + size;
3654
3695
  }
3655
3696
 
3656
- const fileSize = type === 'liFE' ? readLength64(reader) : 0;
3657
- if (type === 'liFA') skipBytes(reader, 8);
3658
- if (type === 'liFD') file.data = readBytes(reader, dataSize); // seems to be a typo in docs
3659
- if (version >= 5) file.childDocumentID = readUnicodeString(reader);
3660
- if (version >= 6) file.assetModTime = readFloat64(reader);
3661
- if (version >= 7) file.assetLockedState = readUint8(reader);
3662
- if (type === 'liFE' && version === 2) file.data = readBytes(reader, fileSize);
3697
+ skipBytes(reader, left()); // ?
3698
+ },
3699
+ (writer, target) => {
3700
+ const psd = target as Psd;
3663
3701
 
3664
- if (reader.skipLinkedFilesData) file.data = undefined;
3702
+ for (const file of psd.linkedFiles!) {
3703
+ if ((tag === 'lnkE') !== !!file.linkedFile) continue;
3665
3704
 
3666
- psd.linkedFiles.push(file);
3667
- linkedFileDescriptor;
3705
+ let version = 2;
3668
3706
 
3669
- while (size % 4) size++;
3670
- reader.offset = startOffset + size;
3671
- }
3707
+ if (file.assetLockedState != null) version = 7;
3708
+ else if (file.assetModTime != null) version = 6;
3709
+ else if (file.childDocumentID != null) version = 5;
3710
+ else if (tag == 'lnkE') version = 3;
3672
3711
 
3673
- skipBytes(reader, left()); // ?
3674
- },
3675
- (writer, target) => {
3676
- const psd = target as Psd;
3712
+ writeLength64(writer, 0);
3677
3713
 
3678
- for (const file of psd.linkedFiles!) {
3679
- let version = 2;
3714
+ const sizeOffset = writer.offset;
3715
+ writeSignature(writer, (tag === 'lnkE') ? 'liFE' : (file.data ? 'liFD' : 'liFA'));
3716
+ writeInt32(writer, version);
3717
+ if (!file.id || typeof file.id !== 'string' || !/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/.test(file.id)) {
3718
+ throw new Error('Linked file ID must be in a GUID format (example: 20953ddb-9391-11ec-b4f1-c15674f50bc4)');
3719
+ }
3720
+ writePascalString(writer, file.id, 1);
3721
+ writeUnicodeStringWithPadding(writer, file.name || '');
3722
+ writeSignature(writer, file.type ? `${file.type} `.substring(0, 4) : ' ');
3723
+ writeSignature(writer, file.creator ? `${file.creator} `.substring(0, 4) : '\0\0\0\0');
3724
+ writeLength64(writer, file.data ? file.data.byteLength : 0);
3725
+
3726
+ if (file.descriptor && file.descriptor.compInfo) {
3727
+ const desc: FileOpenDescriptor = {
3728
+ compInfo: {
3729
+ compID: file.descriptor.compInfo.compID,
3730
+ originalCompID: file.descriptor.compInfo.originalCompID,
3731
+ },
3732
+ };
3680
3733
 
3681
- if (file.assetLockedState != null) version = 7;
3682
- else if (file.assetModTime != null) version = 6;
3683
- else if (file.childDocumentID != null) version = 5;
3684
- // TODO: else if (file.time != null) version = 3; (only for liFE)
3734
+ writeUint8(writer, 1);
3735
+ writeVersionAndDescriptor(writer, '', 'null', desc);
3736
+ } else {
3737
+ writeUint8(writer, 0);
3738
+ }
3685
3739
 
3686
- writeUint32(writer, 0);
3687
- writeUint32(writer, 0); // size
3688
- const sizeOffset = writer.offset;
3689
- writeSignature(writer, file.data ? 'liFD' : 'liFA');
3690
- writeInt32(writer, version);
3691
- if (!file.id || typeof file.id !== 'string' || !/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/.test(file.id)) {
3692
- throw new Error('Linked file ID must be in a GUID format (example: 20953ddb-9391-11ec-b4f1-c15674f50bc4)');
3693
- }
3694
- writePascalString(writer, file.id, 1);
3695
- writeUnicodeStringWithPadding(writer, file.name || '');
3696
- writeSignature(writer, file.type ? `${file.type} `.substring(0, 4) : ' ');
3697
- writeSignature(writer, file.creator ? `${file.creator} `.substring(0, 4) : '\0\0\0\0');
3698
- writeLength64(writer, file.data ? file.data.byteLength : 0);
3699
-
3700
- if (file.descriptor && file.descriptor.compInfo) {
3701
- const desc: FileOpenDescriptor = {
3702
- compInfo: {
3703
- compID: file.descriptor.compInfo.compID,
3704
- originalCompID: file.descriptor.compInfo.originalCompID,
3705
- }
3706
- };
3740
+ if (tag === 'lnkE') {
3741
+ const desc: LinkedFileDescriptor = {
3742
+ descVersion: 2,
3743
+ 'Nm ': file.linkedFile?.name ?? '',
3744
+ fullPath: file.linkedFile?.fullPath ?? '',
3745
+ originalPath: file.linkedFile?.originalPath ?? '',
3746
+ relPath: file.linkedFile?.relativePath ?? '',
3747
+ };
3707
3748
 
3708
- writeUint8(writer, 1);
3709
- writeVersionAndDescriptor(writer, '', 'null', desc);
3710
- } else {
3711
- writeUint8(writer, 0);
3712
- }
3749
+ writeVersionAndDescriptor(writer, '', 'ExternalFileLink', desc);
3713
3750
 
3714
- if (file.data) writeBytes(writer, file.data);
3715
- else writeLength64(writer, 0);
3716
- if (version >= 5) writeUnicodeStringWithPadding(writer, file.childDocumentID || '');
3717
- if (version >= 6) writeFloat64(writer, file.assetModTime || 0);
3718
- if (version >= 7) writeUint8(writer, file.assetLockedState || 0);
3751
+ const time = file.time ? new Date(file.time) : new Date();
3752
+ writeInt32(writer, time.getUTCFullYear());
3753
+ writeUint8(writer, time.getUTCMonth());
3754
+ writeUint8(writer, time.getUTCDate());
3755
+ writeUint8(writer, time.getUTCHours());
3756
+ writeUint8(writer, time.getUTCMinutes());
3757
+ writeFloat64(writer, time.getUTCSeconds() + time.getUTCMilliseconds() / 1000);
3758
+ }
3759
+
3760
+ if (file.data) {
3761
+ writeBytes(writer, file.data);
3762
+ } else {
3763
+ writeLength64(writer, file.linkedFile?.fileSize || 0);
3764
+ }
3719
3765
 
3720
- let size = writer.offset - sizeOffset;
3721
- writer.view.setUint32(sizeOffset - 4, size, false); // write size
3766
+ if (version >= 5) writeUnicodeStringWithPadding(writer, file.childDocumentID || '');
3767
+ if (version >= 6) writeFloat64(writer, file.assetModTime || 0);
3768
+ if (version >= 7) writeUint8(writer, file.assetLockedState || 0);
3722
3769
 
3723
- while (size % 4) {
3724
- size++;
3725
- writeUint8(writer, 0);
3770
+ let size = writer.offset - sizeOffset;
3771
+ writer.view.setUint32(sizeOffset - 4, size, false); // write size
3772
+
3773
+ while (size % 4) {
3774
+ size++;
3775
+ writeUint8(writer, 0);
3776
+ }
3726
3777
  }
3727
- }
3728
- },
3729
- );
3778
+ },
3779
+ );
3780
+ }
3781
+
3782
+ createLnkHandler('lnk2');
3783
+ createLnkHandler('lnkE');
3730
3784
 
3731
3785
  addHandlerAlias('lnkD', 'lnk2');
3732
3786
  addHandlerAlias('lnk3', 'lnk2');
3733
- addHandlerAlias('lnkE', 'lnk2');
3734
3787
 
3735
3788
  interface PthsDescriptor {
3736
3789
  pathList: {
package/src/descriptor.ts CHANGED
@@ -178,7 +178,7 @@ const typeToField: { [key: string]: string[]; } = {
178
178
  'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
179
179
  'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
180
180
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
181
- 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment',
181
+ 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath',
182
182
  ],
183
183
  'tdta': [
184
184
  'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
@@ -935,7 +935,13 @@ export interface WarpDescriptor {
935
935
  Left: DescriptorUnitsValue;
936
936
  Btom: DescriptorUnitsValue;
937
937
  Rght: DescriptorUnitsValue;
938
- };
938
+ } | {
939
+ _classID: 'classFloatRect',
940
+ 'Top ': number,
941
+ Left: number,
942
+ Btom: number,
943
+ Rght: number,
944
+ },
939
945
  uOrder: number;
940
946
  vOrder: number;
941
947
  customEnvelopeWarp?: {
package/src/psd.ts CHANGED
@@ -678,7 +678,7 @@ export interface SelectiveColorAdjustment {
678
678
  blacks?: CMYK;
679
679
  }
680
680
 
681
- export interface LinkedFile {
681
+ export type LinkedFile = {
682
682
  id: string; // must be in a GUID format (example: 20953ddb-9391-11ec-b4f1-c15674f50bc4)
683
683
  name: string;
684
684
  type?: string;
@@ -691,6 +691,15 @@ export interface LinkedFile {
691
691
  childDocumentID?: string;
692
692
  assetModTime?: number;
693
693
  assetLockedState?: number;
694
+
695
+ // external files
696
+ linkedFile?: {
697
+ fileSize: number;
698
+ name: string;
699
+ fullPath: string;
700
+ originalPath: string;
701
+ relativePath: string;
702
+ };
694
703
  }
695
704
 
696
705
  type FilterVariant = {
package/src/psdWriter.ts CHANGED
@@ -476,13 +476,6 @@ function addChildren(layers: Layer[], children: Layer[] | undefined) {
476
476
  sectionDivider: {
477
477
  type: SectionDividerType.BoundingSectionDivider,
478
478
  },
479
- // TESTING
480
- // nameSource: 'lset',
481
- // id: [4, 0, 0, 8, 11, 0, 0, 0, 0, 14][layers.length] || 0,
482
- // layerColor: 'none',
483
- // timestamp: [1611346817.349021, 0, 0, 1611346817.349175, 1611346817.3491833, 0, 0, 0, 0, 1611346817.349832][layers.length] || 0,
484
- // protected: {},
485
- // referencePoint: { x: 0, y: 0 },
486
479
  });
487
480
  addChildren(layers, c.children);
488
481
  layers.push({