ag-psd 19.0.0 → 20.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/CHANGELOG.md +8 -0
- package/README_PSD.md +6 -0
- package/TODO +5 -0
- package/dist/abr.js +4 -4
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +3 -3
- package/dist/additionalInfo.js +99 -10
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +408 -151
- package/dist/descriptor.js +21 -16
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +2 -7
- package/dist/helpers.js +33 -10
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +37 -0
- package/dist/imageResources.js.map +1 -1
- package/dist/psd.d.ts +46 -3
- package/dist/psd.js +8 -1
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.d.ts +11 -5
- package/dist/psdReader.js +179 -97
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.js +27 -13
- package/dist/psdWriter.js.map +1 -1
- package/dist-es/abr.js +4 -4
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +3 -3
- package/dist-es/additionalInfo.js +102 -13
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/descriptor.js +21 -16
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +2 -7
- package/dist-es/helpers.js +31 -9
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +37 -0
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/psd.d.ts +46 -3
- package/dist-es/psd.js +7 -0
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.d.ts +11 -5
- package/dist-es/psdReader.js +178 -99
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.js +28 -14
- package/dist-es/psdWriter.js.map +1 -1
- package/package.json +1 -1
- package/src/abr.ts +4 -4
- package/src/additionalInfo.ts +142 -49
- package/src/descriptor.ts +14 -9
- package/src/helpers.ts +35 -18
- package/src/imageResources.ts +53 -0
- package/src/psd.ts +41 -5
- package/src/psdReader.ts +170 -126
- package/src/psdWriter.ts +36 -23
package/src/additionalInfo.ts
CHANGED
|
@@ -1,37 +1,10 @@
|
|
|
1
1
|
import { fromByteArray, toByteArray } from 'base64-js';
|
|
2
2
|
import { readEffects, writeEffects } from './effectsHelpers';
|
|
3
3
|
import { clamp, createEnum, layerColors, MOCK_HANDLERS } from './helpers';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment,
|
|
9
|
-
CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel,
|
|
10
|
-
PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem,
|
|
11
|
-
BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter,
|
|
12
|
-
UnitsValue, Filter, PlacedLayer,
|
|
13
|
-
} from './psd';
|
|
14
|
-
import {
|
|
15
|
-
PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16,
|
|
16
|
-
readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32,
|
|
17
|
-
readPascalString, readUnicodeStringWithLength, readAsciiString, readPattern,
|
|
18
|
-
} from './psdReader';
|
|
19
|
-
import {
|
|
20
|
-
PsdWriter, writeZeros, writeSignature, writeBytes, writeUint32, writeUint16, writeFloat64, writeUint8,
|
|
21
|
-
writeInt16, writeFloat32, writeFixedPointPath32, writeUnicodeString, writeSection, writeUnicodeStringWithPadding,
|
|
22
|
-
writeColor, writePascalString, writeInt32,
|
|
23
|
-
} from './psdWriter';
|
|
24
|
-
import {
|
|
25
|
-
Annt, BlnM, DescriptorColor, DescriptorUnitsValue, parsePercent, parseUnits, parseUnitsOrNumber, QuiltWarpDescriptor,
|
|
26
|
-
strokeStyleLineAlignment, strokeStyleLineCapType, strokeStyleLineJoinType, TextDescriptor, textGridding,
|
|
27
|
-
unitsPercent, unitsValue, WarpDescriptor, warpStyle, writeVersionAndDescriptor,
|
|
28
|
-
readVersionAndDescriptor, StrokeDescriptor, Ornt, horzVrtcToXY, LmfxDescriptor, Lfx2Descriptor,
|
|
29
|
-
FrameListDescriptor, TimelineDescriptor, FrameDescriptor, xyToHorzVrtc, serializeEffects,
|
|
30
|
-
parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList,
|
|
31
|
-
serializeTrackList, FractionDescriptor, BlrM, BlrQ, SmBQ, SmBM, DspM, UndA, Cnvr, RplS, SphM, Wvtp, ZZTy,
|
|
32
|
-
Dstr, Chnl, MztT, Lns, blurType, DfsM, ExtT, ExtR, FlCl, CntE, WndM, Drct, IntE, IntC, FlMd,
|
|
33
|
-
unitsPercentF, frac, ClrS, descBoundsToBounds, boundsToDescBounds,
|
|
34
|
-
} from './descriptor';
|
|
4
|
+
import { LayerAdditionalInfo, BezierPath, Psd, BrightnessAdjustment, ExposureAdjustment, VibranceAdjustment, ColorBalanceAdjustment, BlackAndWhiteAdjustment, PhotoFilterAdjustment, ChannelMixerChannel, ChannelMixerAdjustment, PosterizeAdjustment, ThresholdAdjustment, GradientMapAdjustment, CMYK, SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment, CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel, PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem, BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer } from './psd';
|
|
5
|
+
import { PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16, readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32, readPascalString, readUnicodeStringWithLength, readAsciiString, readPattern, readLayerInfo, ReadOptionsExt } from './psdReader';
|
|
6
|
+
import { PsdWriter, writeZeros, writeSignature, writeBytes, writeUint32, writeUint16, writeFloat64, writeUint8, writeInt16, writeFloat32, writeFixedPointPath32, writeUnicodeString, writeSection, writeUnicodeStringWithPadding, writeColor, writePascalString, writeInt32 } from './psdWriter';
|
|
7
|
+
import { Annt, BlnM, DescriptorColor, DescriptorUnitsValue, parsePercent, parseUnits, parseUnitsOrNumber, QuiltWarpDescriptor, strokeStyleLineAlignment, strokeStyleLineCapType, strokeStyleLineJoinType, TextDescriptor, textGridding, unitsPercent, unitsValue, WarpDescriptor, warpStyle, writeVersionAndDescriptor, readVersionAndDescriptor, StrokeDescriptor, Ornt, horzVrtcToXY, LmfxDescriptor, Lfx2Descriptor, FrameListDescriptor, TimelineDescriptor, FrameDescriptor, xyToHorzVrtc, serializeEffects, parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList, serializeTrackList, FractionDescriptor, BlrM, BlrQ, SmBQ, SmBM, DspM, UndA, Cnvr, RplS, SphM, Wvtp, ZZTy, Dstr, Chnl, MztT, Lns, blurType, DfsM, ExtT, ExtR, FlCl, CntE, WndM, Drct, IntE, IntC, FlMd, unitsPercentF, frac, ClrS, descBoundsToBounds, boundsToDescBounds } from './descriptor';
|
|
35
8
|
import { serializeEngineData, parseEngineData } from './engineData';
|
|
36
9
|
import { encodeEngineData, decodeEngineData } from './text';
|
|
37
10
|
|
|
@@ -41,7 +14,7 @@ export interface ExtendedWriteOptions extends WriteOptions {
|
|
|
41
14
|
}
|
|
42
15
|
|
|
43
16
|
type HasMethod = (target: LayerAdditionalInfo) => boolean;
|
|
44
|
-
type ReadMethod = (reader: PsdReader, target: LayerAdditionalInfo, left: () => number, psd: Psd, options:
|
|
17
|
+
type ReadMethod = (reader: PsdReader, target: LayerAdditionalInfo, left: () => number, psd: Psd, options: ReadOptionsExt) => void;
|
|
45
18
|
type WriteMethod = (writer: PsdWriter, target: LayerAdditionalInfo, psd: Psd, options: ExtendedWriteOptions) => void;
|
|
46
19
|
|
|
47
20
|
export interface InfoHandler {
|
|
@@ -90,9 +63,11 @@ addHandler(
|
|
|
90
63
|
|
|
91
64
|
if (readInt16(reader) !== 50) throw new Error(`Invalid TySh text version`);
|
|
92
65
|
const text: TextDescriptor = readVersionAndDescriptor(reader);
|
|
66
|
+
// console.log(require('util').inspect(text, false, 99, false), 'utf8');
|
|
93
67
|
|
|
94
68
|
if (readInt16(reader) !== 1) throw new Error(`Invalid TySh warp version`);
|
|
95
69
|
const warp: WarpDescriptor = readVersionAndDescriptor(reader);
|
|
70
|
+
// console.log(require('util').inspect(warp, false, 99, false), 'utf8');
|
|
96
71
|
|
|
97
72
|
target.text = {
|
|
98
73
|
transform,
|
|
@@ -120,6 +95,7 @@ addHandler(
|
|
|
120
95
|
if (text.EngineData) {
|
|
121
96
|
const engineData = parseEngineData(text.EngineData);
|
|
122
97
|
const textData = decodeEngineData(engineData);
|
|
98
|
+
// console.log(require('util').inspect(engineData, false, 99, false), 'utf8');
|
|
123
99
|
|
|
124
100
|
// require('fs').writeFileSync(`layer-${target.name}.txt`, require('util').inspect(engineData, false, 99, false), 'utf8');
|
|
125
101
|
// const before = parseEngineData(text.EngineData);
|
|
@@ -732,10 +708,21 @@ interface CustomDescriptor {
|
|
|
732
708
|
layerTime?: number;
|
|
733
709
|
}
|
|
734
710
|
|
|
711
|
+
interface CmlsDescriptor {
|
|
712
|
+
origFXRefPoint?: { Hrzn: number; Vrtc: number; };
|
|
713
|
+
LyrI: number;
|
|
714
|
+
layerSettings: {
|
|
715
|
+
enab?: boolean;
|
|
716
|
+
Ofst?: { Hrzn: number; Vrtc: number; };
|
|
717
|
+
FXRefPoint?: { Hrzn: number; Vrtc: number; };
|
|
718
|
+
compList: number[];
|
|
719
|
+
}[];
|
|
720
|
+
}
|
|
721
|
+
|
|
735
722
|
addHandler(
|
|
736
723
|
'shmd',
|
|
737
724
|
target => target.timestamp !== undefined || target.animationFrames !== undefined ||
|
|
738
|
-
target.animationFrameFlags !== undefined || target.timeline !== undefined,
|
|
725
|
+
target.animationFrameFlags !== undefined || target.timeline !== undefined || target.comps !== undefined,
|
|
739
726
|
(reader, target, left, _, options) => {
|
|
740
727
|
const count = readUint32(reader);
|
|
741
728
|
|
|
@@ -798,8 +785,25 @@ addHandler(
|
|
|
798
785
|
|
|
799
786
|
target.timeline = timeline;
|
|
800
787
|
// console.log('tmln:result', target.name, target.id, require('util').inspect(timeline, false, 99, true));
|
|
788
|
+
} else if (key === 'cmls') {
|
|
789
|
+
const desc = readVersionAndDescriptor(reader) as CmlsDescriptor;
|
|
790
|
+
// console.log('cmls', require('util').inspect(desc, false, 99, true));
|
|
791
|
+
|
|
792
|
+
target.comps = {
|
|
793
|
+
settings: [],
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
if (desc.origFXRefPoint) target.comps.originalEffectsReferencePoint = { x: desc.origFXRefPoint.Hrzn, y: desc.origFXRefPoint.Vrtc };
|
|
797
|
+
|
|
798
|
+
for (const item of desc.layerSettings) {
|
|
799
|
+
target.comps.settings.push({ compList: item.compList });
|
|
800
|
+
const t = target.comps.settings[target.comps.settings.length - 1];
|
|
801
|
+
if ('enab' in item) t.enabled = item.enab;
|
|
802
|
+
if (item.Ofst) t.offset = { x: item.Ofst.Hrzn, y: item.Ofst.Vrtc };
|
|
803
|
+
if (item.FXRefPoint) t.effectsReferencePoint = { x: item.FXRefPoint.Hrzn, y: item.FXRefPoint.Vrtc };
|
|
804
|
+
}
|
|
801
805
|
} else {
|
|
802
|
-
options.
|
|
806
|
+
options.logMissingFeatures && console.log('Unhandled "shmd" section key', key);
|
|
803
807
|
}
|
|
804
808
|
|
|
805
809
|
skipBytes(reader, left());
|
|
@@ -809,13 +813,14 @@ addHandler(
|
|
|
809
813
|
skipBytes(reader, left());
|
|
810
814
|
},
|
|
811
815
|
(writer, target, _, options) => {
|
|
812
|
-
const { animationFrames, animationFrameFlags, timestamp, timeline } = target;
|
|
816
|
+
const { animationFrames, animationFrameFlags, timestamp, timeline, comps } = target;
|
|
813
817
|
|
|
814
818
|
let count = 0;
|
|
815
819
|
if (animationFrames) count++;
|
|
816
820
|
if (animationFrameFlags) count++;
|
|
817
821
|
if (timeline) count++;
|
|
818
822
|
if (timestamp !== undefined) count++;
|
|
823
|
+
if (comps) count++;
|
|
819
824
|
writeUint32(writer, count);
|
|
820
825
|
|
|
821
826
|
if (animationFrames) {
|
|
@@ -883,7 +888,7 @@ addHandler(
|
|
|
883
888
|
desc.trackList = serializeTrackList(timeline.tracks);
|
|
884
889
|
}
|
|
885
890
|
|
|
886
|
-
const id = options.layerToId.get(target) || target.id
|
|
891
|
+
const id = options.layerToId.get(target) || target.id;
|
|
887
892
|
if (!id) throw new Error('You need to provide layer.id value whan writing document with animations');
|
|
888
893
|
desc.LyrI = id;
|
|
889
894
|
|
|
@@ -904,6 +909,38 @@ addHandler(
|
|
|
904
909
|
writeVersionAndDescriptor(writer, '', 'metadata', desc);
|
|
905
910
|
}, true);
|
|
906
911
|
}
|
|
912
|
+
|
|
913
|
+
if (comps) {
|
|
914
|
+
writeSignature(writer, '8BIM');
|
|
915
|
+
writeSignature(writer, 'cmls');
|
|
916
|
+
writeUint8(writer, 0); // copy (always false)
|
|
917
|
+
writeZeros(writer, 3);
|
|
918
|
+
writeSection(writer, 2, () => {
|
|
919
|
+
const id = options.layerToId.get(target) || target.id;
|
|
920
|
+
if (!id) throw new Error('You need to provide layer.id value whan writing document with layer comps');
|
|
921
|
+
|
|
922
|
+
const desc: CmlsDescriptor = {} as any;
|
|
923
|
+
|
|
924
|
+
if (comps.originalEffectsReferencePoint) {
|
|
925
|
+
desc.origFXRefPoint = { Hrzn: comps.originalEffectsReferencePoint.x, Vrtc: comps.originalEffectsReferencePoint.y };
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
desc.LyrI = id;
|
|
929
|
+
desc.layerSettings = [];
|
|
930
|
+
|
|
931
|
+
for (const item of comps.settings) {
|
|
932
|
+
const t: CmlsDescriptor['layerSettings'][0] = {} as any;
|
|
933
|
+
if (item.enabled !== undefined) t.enab = item.enabled;
|
|
934
|
+
if (item.offset) t.Ofst = { Hrzn: item.offset.x, Vrtc: item.offset.y };
|
|
935
|
+
if (item.effectsReferencePoint) t.FXRefPoint = { Hrzn: item.effectsReferencePoint.x, Vrtc: item.effectsReferencePoint.y };
|
|
936
|
+
t.compList = item.compList;
|
|
937
|
+
desc.layerSettings.push(t);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// console.log('cmls', require('util').inspect(desc, false, 99, true));
|
|
941
|
+
writeVersionAndDescriptor(writer, '', 'null', desc);
|
|
942
|
+
}, true);
|
|
943
|
+
}
|
|
907
944
|
},
|
|
908
945
|
);
|
|
909
946
|
|
|
@@ -3304,6 +3341,52 @@ addHandler(
|
|
|
3304
3341
|
},
|
|
3305
3342
|
);
|
|
3306
3343
|
|
|
3344
|
+
addHandler(
|
|
3345
|
+
'Lr16',
|
|
3346
|
+
() => false,
|
|
3347
|
+
(reader, _target, _left, psd, options) => {
|
|
3348
|
+
readLayerInfo(reader, psd, options);
|
|
3349
|
+
},
|
|
3350
|
+
(_writer, _target) => {
|
|
3351
|
+
},
|
|
3352
|
+
);
|
|
3353
|
+
|
|
3354
|
+
addHandler(
|
|
3355
|
+
'LMsk',
|
|
3356
|
+
hasKey('userMask'),
|
|
3357
|
+
(reader, target) => {
|
|
3358
|
+
target.userMask = {
|
|
3359
|
+
colorSpace: readColor(reader),
|
|
3360
|
+
opacity: readUint16(reader) / 0xff,
|
|
3361
|
+
};
|
|
3362
|
+
const flag = readUint8(reader);
|
|
3363
|
+
if (flag !== 128) throw new Error('Invalid flag value');
|
|
3364
|
+
skipBytes(reader, 1);
|
|
3365
|
+
},
|
|
3366
|
+
(writer, target) => {
|
|
3367
|
+
const userMask = target.userMask!;
|
|
3368
|
+
writeColor(writer, userMask.colorSpace);
|
|
3369
|
+
writeUint16(writer, clamp(userMask.opacity, 0, 1) * 0xff);
|
|
3370
|
+
writeUint8(writer, 128);
|
|
3371
|
+
writeZeros(writer, 1);
|
|
3372
|
+
},
|
|
3373
|
+
);
|
|
3374
|
+
|
|
3375
|
+
if (MOCK_HANDLERS) {
|
|
3376
|
+
addHandler(
|
|
3377
|
+
'vowv', // appears with Lr16 section ?
|
|
3378
|
+
_ => false,
|
|
3379
|
+
(reader, target, left) => {
|
|
3380
|
+
const value = readUint32(reader); // 2 ????
|
|
3381
|
+
reader; target;
|
|
3382
|
+
console.log('vowv', { value }, left());
|
|
3383
|
+
},
|
|
3384
|
+
(_writer, _target) => {
|
|
3385
|
+
// TODO: write
|
|
3386
|
+
},
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
|
|
3307
3390
|
if (MOCK_HANDLERS) {
|
|
3308
3391
|
addHandler(
|
|
3309
3392
|
'Patt',
|
|
@@ -3614,30 +3697,33 @@ addHandlerAlias('lnkD', 'lnk2');
|
|
|
3614
3697
|
addHandlerAlias('lnk3', 'lnk2');
|
|
3615
3698
|
addHandlerAlias('lnkE', 'lnk2');
|
|
3616
3699
|
|
|
3617
|
-
interface
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3700
|
+
interface PthsDescriptor {
|
|
3701
|
+
pathList: {
|
|
3702
|
+
_classID: 'pathInfoClass';
|
|
3703
|
+
pathUnicodeName: string;
|
|
3704
|
+
pathSymmetryClass: {
|
|
3705
|
+
_classID: 'pathSymmetryClass';
|
|
3706
|
+
pathSymmetryMode: string; // 'pathSymmetryModeEnum.pathSymmetryModeBasicPath'
|
|
3707
|
+
};
|
|
3708
|
+
}[];
|
|
3622
3709
|
}
|
|
3623
3710
|
|
|
3624
3711
|
addHandler(
|
|
3625
3712
|
'pths',
|
|
3626
3713
|
hasKey('pathList'),
|
|
3627
3714
|
(reader, target) => {
|
|
3628
|
-
const
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
// console.log('pths', descriptor); // TODO: remove this
|
|
3715
|
+
const desc = readVersionAndDescriptor(reader, true) as PthsDescriptor;
|
|
3716
|
+
// console.log(require('util').inspect(desc, false, 99, true));
|
|
3717
|
+
// if (options.throwForMissingFeatures && desc?.pathList?.length) throw new Error('non-empty pathList in `pths`');
|
|
3718
|
+
desc;
|
|
3719
|
+
target.pathList = []; // TODO: read paths
|
|
3634
3720
|
},
|
|
3635
3721
|
(writer, _target) => {
|
|
3636
|
-
const
|
|
3722
|
+
const desc: PthsDescriptor = {
|
|
3637
3723
|
pathList: [], // TODO: write paths
|
|
3638
3724
|
};
|
|
3639
3725
|
|
|
3640
|
-
writeVersionAndDescriptor(writer, '', 'pathsDataClass',
|
|
3726
|
+
writeVersionAndDescriptor(writer, '', 'pathsDataClass', desc);
|
|
3641
3727
|
},
|
|
3642
3728
|
);
|
|
3643
3729
|
|
|
@@ -4804,6 +4890,13 @@ addHandler(
|
|
|
4804
4890
|
},
|
|
4805
4891
|
);
|
|
4806
4892
|
|
|
4893
|
+
interface ExtensionDesc {
|
|
4894
|
+
generatorSettings: {
|
|
4895
|
+
generator_45_assets: { json: string; };
|
|
4896
|
+
layerTime: number;
|
|
4897
|
+
};
|
|
4898
|
+
}
|
|
4899
|
+
|
|
4807
4900
|
// extension settings ?, ignore it
|
|
4808
4901
|
addHandler(
|
|
4809
4902
|
'extn',
|
package/src/descriptor.ts
CHANGED
|
@@ -136,6 +136,8 @@ const fieldToExtType: ExtTypeDict = {
|
|
|
136
136
|
sdwM: makeType('Parameters', 'adaptCorrectTones'),
|
|
137
137
|
hglM: makeType('Parameters', 'adaptCorrectTones'),
|
|
138
138
|
customShape: makeType('', 'customShape'),
|
|
139
|
+
origFXRefPoint: nullType,
|
|
140
|
+
FXRefPoint: nullType,
|
|
139
141
|
};
|
|
140
142
|
|
|
141
143
|
const fieldToArrayExtType: ExtTypeDict = {
|
|
@@ -167,6 +169,8 @@ const fieldToArrayExtType: ExtTypeDict = {
|
|
|
167
169
|
puppetShapeList: makeType('', 'puppetShape'),
|
|
168
170
|
channelDenoise: makeType('', 'channelDenoiseParams'),
|
|
169
171
|
ShrP: makeType('', 'Pnt '),
|
|
172
|
+
layerSettings: nullType,
|
|
173
|
+
list: nullType,
|
|
170
174
|
};
|
|
171
175
|
|
|
172
176
|
const typeToField: { [key: string]: string[]; } = {
|
|
@@ -174,7 +178,7 @@ const typeToField: { [key: string]: string[]; } = {
|
|
|
174
178
|
'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
|
|
175
179
|
'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
|
|
176
180
|
'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
|
|
177
|
-
'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth',
|
|
181
|
+
'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment',
|
|
178
182
|
],
|
|
179
183
|
'tdta': [
|
|
180
184
|
'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
|
|
@@ -192,7 +196,7 @@ const typeToField: { [key: string]: string[]; } = {
|
|
|
192
196
|
'topOutset', 'leftOutset', 'bottomOutset', 'rightOutset', 'filterID', 'meshQuality',
|
|
193
197
|
'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
|
|
194
198
|
'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
|
|
195
|
-
'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4',
|
|
199
|
+
'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
|
|
196
200
|
],
|
|
197
201
|
'enum': [
|
|
198
202
|
'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
|
|
@@ -237,7 +241,7 @@ const typeToField: { [key: string]: string[]; } = {
|
|
|
237
241
|
'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
|
|
238
242
|
'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
|
|
239
243
|
'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList', 'ShrP',
|
|
240
|
-
'channelDenoise', 'Mtrx',
|
|
244
|
+
'channelDenoise', 'Mtrx', 'layerSettings', 'list', 'compList',
|
|
241
245
|
],
|
|
242
246
|
'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
|
|
243
247
|
'obj ': ['null', 'Chnl'],
|
|
@@ -285,6 +289,7 @@ const fieldToArrayType: Dict = {
|
|
|
285
289
|
ShrP: 'Objc',
|
|
286
290
|
channelDenoise: 'Objc',
|
|
287
291
|
Mtrx: 'long',
|
|
292
|
+
compList: 'long',
|
|
288
293
|
};
|
|
289
294
|
|
|
290
295
|
const fieldToType: Dict = {};
|
|
@@ -336,7 +341,7 @@ export function readAsciiStringOrClassId(reader: PsdReader) {
|
|
|
336
341
|
}
|
|
337
342
|
|
|
338
343
|
function writeAsciiStringOrClassId(writer: PsdWriter, value: string) {
|
|
339
|
-
if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold') {
|
|
344
|
+
if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list') {
|
|
340
345
|
// write classId
|
|
341
346
|
writeInt32(writer, 0);
|
|
342
347
|
writeSignature(writer, value);
|
|
@@ -473,9 +478,9 @@ function readOSType(reader: PsdReader, type: string, includeClass: boolean) {
|
|
|
473
478
|
const items: any[] = [];
|
|
474
479
|
|
|
475
480
|
for (let i = 0; i < length; i++) {
|
|
476
|
-
const
|
|
477
|
-
// console.log(' >',
|
|
478
|
-
items.push(readOSType(reader,
|
|
481
|
+
const itemType = readSignature(reader);
|
|
482
|
+
// console.log(' >', itemType);
|
|
483
|
+
items.push(readOSType(reader, itemType, includeClass));
|
|
479
484
|
}
|
|
480
485
|
|
|
481
486
|
return items;
|
|
@@ -497,9 +502,9 @@ function readOSType(reader: PsdReader, type: string, includeClass: boolean) {
|
|
|
497
502
|
case 'TEXT': // String
|
|
498
503
|
return readUnicodeString(reader);
|
|
499
504
|
case 'enum': { // Enumerated
|
|
500
|
-
const
|
|
505
|
+
const enumType = readAsciiStringOrClassId(reader);
|
|
501
506
|
const value = readAsciiStringOrClassId(reader);
|
|
502
|
-
return `${
|
|
507
|
+
return `${enumType}.${value}`;
|
|
503
508
|
}
|
|
504
509
|
case 'long': // Integer
|
|
505
510
|
return readInt32(reader);
|
package/src/helpers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromByteArray } from 'base64-js';
|
|
2
2
|
import { deflate } from 'pako';
|
|
3
|
-
import { Layer, BlendMode, LayerColor } from './psd';
|
|
3
|
+
import { Layer, BlendMode, LayerColor, PixelData, PixelArray } from './psd';
|
|
4
4
|
|
|
5
5
|
export const MOCK_HANDLERS = false;
|
|
6
6
|
export const RAW_IMAGE_DATA = false;
|
|
@@ -138,14 +138,6 @@ export interface LayerChannelData {
|
|
|
138
138
|
mask?: Bounds;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
export type PixelArray = Uint8ClampedArray | Uint8Array;
|
|
142
|
-
|
|
143
|
-
export interface PixelData {
|
|
144
|
-
data: PixelArray;
|
|
145
|
-
width: number;
|
|
146
|
-
height: number;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
141
|
export function offsetForChannel(channelId: ChannelID, cmyk: boolean) {
|
|
150
142
|
switch (channelId) {
|
|
151
143
|
case ChannelID.Color0: return 0;
|
|
@@ -174,26 +166,51 @@ export function hasAlpha(data: PixelData) {
|
|
|
174
166
|
}
|
|
175
167
|
|
|
176
168
|
export function resetImageData({ data }: PixelData) {
|
|
177
|
-
const
|
|
178
|
-
|
|
169
|
+
const alpha = (data instanceof Uint32Array) ? (0xffffffff >>> 0) : ((data instanceof Uint16Array) ? 0xffff : 0xff);
|
|
170
|
+
|
|
171
|
+
for (let p = 0, size = data.length | 0; p < size; p = (p + 4) | 0) {
|
|
172
|
+
data[p + 0] = 0;
|
|
173
|
+
data[p + 1] = 0;
|
|
174
|
+
data[p + 2] = 0;
|
|
175
|
+
data[p + 3] = alpha;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
179
178
|
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
export function imageDataToCanvas(pixelData: PixelData) {
|
|
180
|
+
const canvas = createCanvas(pixelData.width, pixelData.height);
|
|
181
|
+
let imageData: ImageData;
|
|
182
|
+
|
|
183
|
+
if (pixelData.data instanceof Uint8ClampedArray) {
|
|
184
|
+
imageData = pixelData as ImageData;
|
|
185
|
+
} else {
|
|
186
|
+
imageData = createImageData(pixelData.width, pixelData.height);
|
|
187
|
+
const src = pixelData.data;
|
|
188
|
+
const dst = imageData.data;
|
|
189
|
+
const shift = (src instanceof Uint32Array) ? 24 : ((src instanceof Uint16Array) ? 8 : 0);
|
|
190
|
+
|
|
191
|
+
for (let i = 0, size = src.length; i < size; i++) {
|
|
192
|
+
dst[i] = src[i] >>> shift;
|
|
193
|
+
}
|
|
182
194
|
}
|
|
195
|
+
|
|
196
|
+
canvas.getContext('2d')!.putImageData(imageData, 0, 0);
|
|
197
|
+
return canvas;
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
export function decodeBitmap(input: PixelArray, output: PixelArray, width: number, height: number) {
|
|
201
|
+
if (input instanceof Uint32Array || input instanceof Uint16Array) throw new Error('Invalid bit depth');
|
|
202
|
+
|
|
186
203
|
for (let y = 0, p = 0, o = 0; y < height; y++) {
|
|
187
204
|
for (let x = 0; x < width;) {
|
|
188
205
|
let b = input[o++];
|
|
189
206
|
|
|
190
|
-
for (let i = 0; i < 8 && x < width; i++, x
|
|
207
|
+
for (let i = 0; i < 8 && x < width; i++, x++, p += 4) {
|
|
191
208
|
const v = b & 0x80 ? 0 : 255;
|
|
192
209
|
b = b << 1;
|
|
193
|
-
output[p
|
|
194
|
-
output[p
|
|
195
|
-
output[p
|
|
196
|
-
output[p
|
|
210
|
+
output[p + 0] = v;
|
|
211
|
+
output[p + 1] = v;
|
|
212
|
+
output[p + 2] = v;
|
|
213
|
+
output[p + 3] = 255;
|
|
197
214
|
}
|
|
198
215
|
}
|
|
199
216
|
}
|
package/src/imageResources.ts
CHANGED
|
@@ -566,6 +566,59 @@ addHandler(
|
|
|
566
566
|
},
|
|
567
567
|
);
|
|
568
568
|
|
|
569
|
+
interface LayerCompsDescriptor {
|
|
570
|
+
list: {
|
|
571
|
+
_classID: 'Comp';
|
|
572
|
+
'Nm ': string;
|
|
573
|
+
compID: number;
|
|
574
|
+
capturedInfo: number;
|
|
575
|
+
comment?: string;
|
|
576
|
+
}[];
|
|
577
|
+
lastAppliedComp?: number;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
addHandler(
|
|
581
|
+
1065, // Layer Comps
|
|
582
|
+
target => target.layerComps !== undefined,
|
|
583
|
+
(reader, target) => {
|
|
584
|
+
const desc = readVersionAndDescriptor(reader, true) as LayerCompsDescriptor;
|
|
585
|
+
// console.log('CompList', require('util').inspect(desc, false, 99, true));
|
|
586
|
+
|
|
587
|
+
target.layerComps = { list: [] };
|
|
588
|
+
|
|
589
|
+
for (const item of desc.list) {
|
|
590
|
+
target.layerComps.list.push({
|
|
591
|
+
id: item.compID,
|
|
592
|
+
name: item['Nm '],
|
|
593
|
+
capturedInfo: item.capturedInfo,
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
if ('comment' in item) target.layerComps.list[target.layerComps.list.length - 1].comment = item.comment;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if ('lastAppliedComp' in desc) target.layerComps.lastApplied = desc.lastAppliedComp;
|
|
600
|
+
},
|
|
601
|
+
(writer, target) => {
|
|
602
|
+
const layerComps = target.layerComps!;
|
|
603
|
+
const desc: LayerCompsDescriptor = { list: [] };
|
|
604
|
+
|
|
605
|
+
for (const item of layerComps.list) {
|
|
606
|
+
const t: LayerCompsDescriptor['list'][0] = {} as any;
|
|
607
|
+
t._classID = 'Comp';
|
|
608
|
+
t['Nm '] = item.name;
|
|
609
|
+
if ('comment' in item) t.comment = item.comment;
|
|
610
|
+
t.compID = item.id;
|
|
611
|
+
t.capturedInfo = item.capturedInfo;
|
|
612
|
+
desc.list.push(t);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if ('lastApplied' in layerComps) desc.lastAppliedComp = layerComps.lastApplied;
|
|
616
|
+
|
|
617
|
+
// console.log('CompList', require('util').inspect(desc, false, 99, true));
|
|
618
|
+
writeVersionAndDescriptor(writer, '', 'CompList', desc);
|
|
619
|
+
},
|
|
620
|
+
);
|
|
621
|
+
|
|
569
622
|
MOCK_HANDLERS && addHandler(
|
|
570
623
|
1092, // ???
|
|
571
624
|
target => (target as any)._ir1092 !== undefined,
|
package/src/psd.ts
CHANGED
|
@@ -24,7 +24,7 @@ export const enum SectionDividerType {
|
|
|
24
24
|
|
|
25
25
|
export type RGBA = { r: number; g: number; b: number; a: number; }; // values from 0 to 255
|
|
26
26
|
export type RGB = { r: number; g: number; b: number; }; // values from 0 to 255
|
|
27
|
-
export type FRGB = { fr: number; fg: number; fb: number; }; // values from 0 to 1 (can be above 1)
|
|
27
|
+
export type FRGB = { fr: number; fg: number; fb: number; }; // values from 0 to 1 (can be above 1, can be negative)
|
|
28
28
|
export type HSB = { h: number; s: number; b: number; }; // values from 0 to 1
|
|
29
29
|
export type CMYK = { c: number; m: number; y: number; k: number; }; // values from 0 to 255
|
|
30
30
|
export type LAB = { l: number; a: number; b: number; }; // values `l` from 0 to 1; `a` and `b` from -1 to 1
|
|
@@ -222,6 +222,14 @@ export interface LayerEffectsInfo {
|
|
|
222
222
|
patternOverlay?: LayerEffectPatternOverlay; // not supported yet because of `Patt` section not implemented
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
export type PixelArray = Uint8ClampedArray | Uint8Array | Uint16Array | Uint32Array;
|
|
226
|
+
|
|
227
|
+
export interface PixelData {
|
|
228
|
+
data: PixelArray; // type depends on document bit depth
|
|
229
|
+
width: number;
|
|
230
|
+
height: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
225
233
|
export interface LayerMaskData {
|
|
226
234
|
top?: number;
|
|
227
235
|
left?: number;
|
|
@@ -236,7 +244,7 @@ export interface LayerMaskData {
|
|
|
236
244
|
vectorMaskDensity?: number;
|
|
237
245
|
vectorMaskFeather?: number;
|
|
238
246
|
canvas?: HTMLCanvasElement;
|
|
239
|
-
imageData?:
|
|
247
|
+
imageData?: PixelData;
|
|
240
248
|
}
|
|
241
249
|
|
|
242
250
|
export type TextGridding = 'none' | 'round'; // TODO: other values (no idea where to set it up in Photoshop)
|
|
@@ -416,7 +424,6 @@ export interface LayerTextData {
|
|
|
416
424
|
shapeType?: 'point' | 'box';
|
|
417
425
|
pointBase?: number[];
|
|
418
426
|
boxBounds?: number[];
|
|
419
|
-
|
|
420
427
|
bounds?: UnitsBounds;
|
|
421
428
|
boundingBox?: UnitsBounds;
|
|
422
429
|
}
|
|
@@ -1385,12 +1392,32 @@ export interface LayerAdditionalInfo {
|
|
|
1385
1392
|
data: Uint8Array;
|
|
1386
1393
|
};
|
|
1387
1394
|
}[];
|
|
1395
|
+
comps?: {
|
|
1396
|
+
originalEffectsReferencePoint?: { x: number; y: number; };
|
|
1397
|
+
settings: {
|
|
1398
|
+
enabled?: boolean;
|
|
1399
|
+
compList: number[];
|
|
1400
|
+
offset?: { x: number; y: number; };
|
|
1401
|
+
effectsReferencePoint?: { x: number; y: number; };
|
|
1402
|
+
}[];
|
|
1403
|
+
};
|
|
1404
|
+
userMask?: {
|
|
1405
|
+
colorSpace: Color;
|
|
1406
|
+
opacity: number;
|
|
1407
|
+
};
|
|
1388
1408
|
|
|
1389
1409
|
// Base64 encoded raw EngineData, currently just kept in original state to support
|
|
1390
1410
|
// loading and modifying PSD file without breaking text layers.
|
|
1391
1411
|
engineData?: string;
|
|
1392
1412
|
}
|
|
1393
1413
|
|
|
1414
|
+
export enum LayerCompCapturedInfo {
|
|
1415
|
+
None = 0,
|
|
1416
|
+
Visibility = 1,
|
|
1417
|
+
Position = 2,
|
|
1418
|
+
Appearance = 4,
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1394
1421
|
export interface ImageResources {
|
|
1395
1422
|
layerState?: number;
|
|
1396
1423
|
layersGroup?: number[];
|
|
@@ -1564,6 +1591,15 @@ export interface ImageResources {
|
|
|
1564
1591
|
rightOutset?: number;
|
|
1565
1592
|
}[];
|
|
1566
1593
|
}[];
|
|
1594
|
+
layerComps?: {
|
|
1595
|
+
list: {
|
|
1596
|
+
id: number;
|
|
1597
|
+
name: string;
|
|
1598
|
+
comment?: string;
|
|
1599
|
+
capturedInfo: LayerCompCapturedInfo;
|
|
1600
|
+
}[];
|
|
1601
|
+
lastApplied?: number;
|
|
1602
|
+
};
|
|
1567
1603
|
}
|
|
1568
1604
|
|
|
1569
1605
|
export interface GlobalLayerMaskInfo {
|
|
@@ -1600,7 +1636,7 @@ export interface Layer extends LayerAdditionalInfo {
|
|
|
1600
1636
|
hidden?: boolean;
|
|
1601
1637
|
clipping?: boolean;
|
|
1602
1638
|
canvas?: HTMLCanvasElement;
|
|
1603
|
-
imageData?:
|
|
1639
|
+
imageData?: PixelData;
|
|
1604
1640
|
children?: Layer[];
|
|
1605
1641
|
/** Applies only for layer groups. */
|
|
1606
1642
|
opened?: boolean;
|
|
@@ -1614,7 +1650,7 @@ export interface Psd extends LayerAdditionalInfo {
|
|
|
1614
1650
|
colorMode?: ColorMode;
|
|
1615
1651
|
children?: Layer[];
|
|
1616
1652
|
canvas?: HTMLCanvasElement;
|
|
1617
|
-
imageData?:
|
|
1653
|
+
imageData?: PixelData;
|
|
1618
1654
|
imageResources?: ImageResources;
|
|
1619
1655
|
linkedFiles?: LinkedFile[]; // used in smart objects
|
|
1620
1656
|
artboards?: {
|