ag-psd 33.0.0 → 34.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/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/d13d7610 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
- package/CHANGELOG.md +22 -0
- package/README.md +1 -1
- package/README_PSD.md +25 -9
- package/TODO.md +13 -84
- package/dist/abr.js +12 -7
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +2 -0
- package/dist/additionalInfo.js +361 -75
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +1524 -389
- package/dist/descriptor.d.ts +14 -5
- package/dist/descriptor.js +102 -64
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +6 -0
- package/dist/helpers.js +242 -2
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +84 -3
- package/dist/imageResources.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/psd.d.ts +144 -2
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.js +206 -110
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +1 -0
- package/dist/psdWriter.js +336 -91
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.d.ts +32 -1
- package/dist/text.js +58 -0
- package/dist/text.js.map +1 -1
- package/dist-es/abr.js +12 -7
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +2 -0
- package/dist-es/additionalInfo.js +361 -75
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/descriptor.d.ts +14 -5
- package/dist-es/descriptor.js +102 -64
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +6 -0
- package/dist-es/helpers.js +242 -2
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +84 -3
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/index.d.ts +1 -0
- package/dist-es/index.js +1 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/psd.d.ts +144 -2
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.js +206 -110
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +1 -0
- package/dist-es/psdWriter.js +336 -91
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.d.ts +32 -1
- package/dist-es/text.js +58 -0
- package/dist-es/text.js.map +1 -1
- package/package.json +1 -1
- package/perf.js +312 -9
- package/src/abr.ts +14 -7
- package/src/additionalInfo.ts +433 -87
- package/src/descriptor.ts +103 -58
- package/src/helpers.ts +262 -2
- package/src/imageResources.ts +107 -4
- package/src/index.ts +1 -0
- package/src/psd.ts +115 -2
- package/src/psdReader.ts +226 -108
- package/src/psdWriter.ts +345 -90
- package/src/text.ts +76 -1
package/src/additionalInfo.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { fromByteArray, toByteArray } from 'base64-js';
|
|
2
2
|
import { readEffects, writeEffects } from './effectsHelpers';
|
|
3
3
|
import { clamp, createEnum, layerColors, MOCK_HANDLERS, normalizeLabAB } from './helpers';
|
|
4
|
-
import { LayerAdditionalInfo, LevelsFilterAdjustment, 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, VectorPathData, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer, Layer } from './psd';
|
|
4
|
+
import { LayerAdditionalInfo, LevelsFilterAdjustment, 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, VectorPathData, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer, Layer, CameraRawColors, CameraRawCurvePoint, CameraRawFilterSettings } from './psd';
|
|
5
5
|
import { PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16, readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32, readPascalString, readUnicodeStringWithLength, readAsciiString, readPatternSafe, readLayerInfo } from './psdReader';
|
|
6
6
|
import { PsdWriter, writeZeros, writeSignature, writeBytes, writeUint32, writeUint16, writeFloat64, writeUint8, writeInt16, writeFloat32, writeFixedPointPath32, writeUnicodeString, writeSection, writeUnicodeStringWithPadding, writeColor, writePascalString, writeInt32, writePattern, writeUint64 } 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, presetKindType, gradientInterpolationMethodType, PxScDescriptor } from './descriptor';
|
|
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, presetKindType, gradientInterpolationMethodType, PxScDescriptor, cameraRawFilterClassID, patternColorHandling } from './descriptor';
|
|
8
8
|
import { serializeEngineData, parseEngineData } from './engineData';
|
|
9
|
-
import { encodeEngineData, decodeEngineData } from './text';
|
|
9
|
+
import { encodeEngineData, decodeEngineData, decodeLegacyTextData, LegacyTextData } from './text';
|
|
10
10
|
import { decodeEngineData2 } from './engineData2';
|
|
11
11
|
import type { InternalImageResources } from './imageResources';
|
|
12
12
|
|
|
13
13
|
export interface ExtendedWriteOptions extends WriteOptions {
|
|
14
|
+
colorMode?: number; // color mode of written document
|
|
15
|
+
bitsPerChannel?: number; // bit depth of written document
|
|
14
16
|
layerIds: Set<number>;
|
|
15
17
|
layerToId: Map<any, number>;
|
|
16
18
|
explicitLayerIds?: Set<number>; // ids set on layers in the document (generated ids can't use them)
|
|
@@ -147,15 +149,95 @@ addHandler(
|
|
|
147
149
|
},
|
|
148
150
|
);
|
|
149
151
|
|
|
152
|
+
// type tool info from Photoshop 5.0 and 5.5, converted to regular text data (written as 'TySh')
|
|
153
|
+
addHandler(
|
|
154
|
+
'tySh',
|
|
155
|
+
() => false,
|
|
156
|
+
(reader, target, left) => {
|
|
157
|
+
if (readInt16(reader) !== 1) throw new Error(`Invalid tySh version`);
|
|
158
|
+
|
|
159
|
+
const transform: number[] = [];
|
|
160
|
+
for (let i = 0; i < 6; i++) transform.push(readFloat64(reader));
|
|
161
|
+
|
|
162
|
+
if (readInt16(reader) !== 6) throw new Error(`Invalid tySh font version`);
|
|
163
|
+
|
|
164
|
+
const data: LegacyTextData = { transform, faces: [], styles: [], lines: [], color: { r: 0, g: 0, b: 0 }, antiAlias: false };
|
|
165
|
+
const facesCount = readInt16(reader);
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < facesCount; i++) {
|
|
168
|
+
const mark = readInt16(reader);
|
|
169
|
+
readInt32(reader); // font type
|
|
170
|
+
const name = readPascalString(reader, 1);
|
|
171
|
+
const familyName = readPascalString(reader, 1);
|
|
172
|
+
const styleName = readPascalString(reader, 1);
|
|
173
|
+
const script = readInt16(reader);
|
|
174
|
+
const axesCount = readInt32(reader);
|
|
175
|
+
if (axesCount < 0 || axesCount * 4 > left()) throw new Error(`Invalid tySh design axes count`);
|
|
176
|
+
skipBytes(reader, axesCount * 4);
|
|
177
|
+
data.faces.push({ mark, name, familyName, styleName, script });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const stylesCount = readInt16(reader);
|
|
181
|
+
|
|
182
|
+
for (let i = 0; i < stylesCount; i++) {
|
|
183
|
+
const mark = readInt16(reader);
|
|
184
|
+
const faceMark = readInt16(reader);
|
|
185
|
+
const size = readInt32(reader);
|
|
186
|
+
const tracking = readInt32(reader);
|
|
187
|
+
const kerning = readInt32(reader);
|
|
188
|
+
const leading = readInt32(reader);
|
|
189
|
+
const baselineShift = readInt32(reader);
|
|
190
|
+
const autoKerning = !!readUint8(reader);
|
|
191
|
+
readUint8(reader); // rotate
|
|
192
|
+
data.styles.push({ mark, faceMark, size, tracking, kerning, leading, baselineShift, autoKerning });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
readInt16(reader); // type (0 = point, 1 = paragraph)
|
|
196
|
+
readInt32(reader); // scaling factor
|
|
197
|
+
readInt32(reader); // character count
|
|
198
|
+
readInt32(reader); // horizontal placement
|
|
199
|
+
readInt32(reader); // vertical placement
|
|
200
|
+
readInt32(reader); // select start
|
|
201
|
+
readInt32(reader); // select end
|
|
202
|
+
|
|
203
|
+
const linesCount = readInt16(reader);
|
|
204
|
+
|
|
205
|
+
for (let i = 0; i < linesCount; i++) {
|
|
206
|
+
const charCount = readInt32(reader);
|
|
207
|
+
const orientation = readInt16(reader);
|
|
208
|
+
const alignment = readInt16(reader);
|
|
209
|
+
if (charCount < 0 || charCount * 4 > left()) throw new Error(`Invalid tySh character count`);
|
|
210
|
+
const chars: { code: number; style: number; }[] = [];
|
|
211
|
+
|
|
212
|
+
for (let j = 0; j < charCount; j++) {
|
|
213
|
+
const code = readUint16(reader);
|
|
214
|
+
const style = readInt16(reader);
|
|
215
|
+
chars.push({ code, style });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
data.lines.push({ orientation, alignment, chars });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
data.color = readColor(reader);
|
|
222
|
+
data.antiAlias = !!readUint8(reader);
|
|
223
|
+
|
|
224
|
+
if (!target.text) target.text = decodeLegacyTextData(data);
|
|
225
|
+
|
|
226
|
+
skipBytes(reader, left());
|
|
227
|
+
},
|
|
228
|
+
() => { },
|
|
229
|
+
);
|
|
230
|
+
|
|
150
231
|
// vector fills
|
|
151
232
|
|
|
152
233
|
addHandler(
|
|
153
234
|
'SoCo',
|
|
154
235
|
target => target.vectorFill !== undefined && target.vectorStroke === undefined &&
|
|
155
236
|
target.vectorFill.type === 'color',
|
|
156
|
-
(reader, target) => {
|
|
237
|
+
(reader, target, left) => {
|
|
157
238
|
const descriptor = readVersionAndDescriptor(reader);
|
|
158
239
|
target.vectorFill = parseVectorContent(descriptor);
|
|
240
|
+
skipBytes(reader, left());
|
|
159
241
|
},
|
|
160
242
|
(writer, target) => {
|
|
161
243
|
const { descriptor } = serializeVectorContent(target.vectorFill!);
|
|
@@ -545,12 +627,12 @@ addHandler(
|
|
|
545
627
|
// console.log('READ', require('util').inspect(desc, false, 99, true));
|
|
546
628
|
|
|
547
629
|
// discard if read in 'lrFX' or 'lfx2' section
|
|
548
|
-
target.effects = parseEffects(desc,
|
|
630
|
+
target.effects = parseEffects(desc, reader);
|
|
549
631
|
|
|
550
632
|
skipBytes(reader, left());
|
|
551
633
|
},
|
|
552
|
-
(writer, target
|
|
553
|
-
const desc = serializeEffects(target.effects!,
|
|
634
|
+
(writer, target) => {
|
|
635
|
+
const desc = serializeEffects(target.effects!, writer, true);
|
|
554
636
|
// console.log('WRITE', require('util').inspect(desc, false, 99, true));
|
|
555
637
|
|
|
556
638
|
writeUint32(writer, 0); // version
|
|
@@ -745,6 +827,82 @@ addHandler(
|
|
|
745
827
|
},
|
|
746
828
|
);
|
|
747
829
|
|
|
830
|
+
addHandler(
|
|
831
|
+
'vmgm',
|
|
832
|
+
hasKey('vectorMaskAsGlobalMask'),
|
|
833
|
+
(reader, target) => {
|
|
834
|
+
target.vectorMaskAsGlobalMask = !!readUint8(reader);
|
|
835
|
+
skipBytes(reader, 3);
|
|
836
|
+
},
|
|
837
|
+
(writer, target) => {
|
|
838
|
+
writeUint8(writer, target.vectorMaskAsGlobalMask ? 1 : 0);
|
|
839
|
+
writeZeros(writer, 3);
|
|
840
|
+
},
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
addHandler(
|
|
844
|
+
'ffxi',
|
|
845
|
+
hasKey('foreignEffectId'),
|
|
846
|
+
(reader, target) => {
|
|
847
|
+
target.foreignEffectId = readInt32(reader);
|
|
848
|
+
},
|
|
849
|
+
(writer, target) => {
|
|
850
|
+
writeInt32(writer, target.foreignEffectId!);
|
|
851
|
+
},
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
addHandler(
|
|
855
|
+
'shpa',
|
|
856
|
+
hasKey('patternData'),
|
|
857
|
+
(reader, target, left) => {
|
|
858
|
+
if (readInt32(reader) !== 0) throw new Error(`Invalid shpa version`);
|
|
859
|
+
|
|
860
|
+
const count = readInt32(reader);
|
|
861
|
+
target.patternData = [];
|
|
862
|
+
|
|
863
|
+
for (let i = 0; i < count && left() > 0; i++) {
|
|
864
|
+
const signature = readSignature(reader);
|
|
865
|
+
const key = readSignature(reader);
|
|
866
|
+
const patternsCount = readInt32(reader);
|
|
867
|
+
const copyOnSheetDuplication = !!readUint8(reader);
|
|
868
|
+
skipBytes(reader, 3);
|
|
869
|
+
const patterns: NonNullable<LayerAdditionalInfo['patternData']>[number]['patterns'] = [];
|
|
870
|
+
|
|
871
|
+
for (let j = 0; j < patternsCount && left() > 0; j++) {
|
|
872
|
+
const colorHandling = patternColorHandling.decode('.' + readSignature(reader));
|
|
873
|
+
readPascalString(reader, 1); // name
|
|
874
|
+
const name = readUnicodeString(reader);
|
|
875
|
+
const id = readPascalString(reader, 1);
|
|
876
|
+
patterns.push({ colorHandling, name, id });
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
target.patternData.push({ signature, key, copyOnSheetDuplication, patterns });
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
skipBytes(reader, left());
|
|
883
|
+
},
|
|
884
|
+
(writer, target) => {
|
|
885
|
+
const sets = target.patternData!;
|
|
886
|
+
writeInt32(writer, 0); // version
|
|
887
|
+
writeInt32(writer, sets.length);
|
|
888
|
+
|
|
889
|
+
for (const set of sets) {
|
|
890
|
+
writeSignature(writer, set.signature);
|
|
891
|
+
writeSignature(writer, set.key);
|
|
892
|
+
writeInt32(writer, set.patterns.length);
|
|
893
|
+
writeUint8(writer, set.copyOnSheetDuplication ? 1 : 0);
|
|
894
|
+
writeZeros(writer, 3);
|
|
895
|
+
|
|
896
|
+
for (const pattern of set.patterns) {
|
|
897
|
+
writeSignature(writer, patternColorHandling.encode(pattern.colorHandling).split('.')[1]);
|
|
898
|
+
writePascalString(writer, pattern.name.replace(/[^\x20-\x7e]/g, '?'), 1);
|
|
899
|
+
writeUnicodeString(writer, pattern.name);
|
|
900
|
+
writePascalString(writer, pattern.id, 1);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
);
|
|
905
|
+
|
|
748
906
|
addHandler(
|
|
749
907
|
'lspf',
|
|
750
908
|
hasKey('protected'),
|
|
@@ -891,7 +1049,7 @@ addHandler(
|
|
|
891
1049
|
if (f.enab !== undefined) frame.enable = f.enab;
|
|
892
1050
|
if (f.Ofst) frame.offset = horzVrtcToXY(f.Ofst);
|
|
893
1051
|
if (f.FXRf) frame.referencePoint = horzVrtcToXY(f.FXRf);
|
|
894
|
-
if (f.Lefx) frame.effects = parseEffects(f.Lefx,
|
|
1052
|
+
if (f.Lefx) frame.effects = parseEffects(f.Lefx, reader);
|
|
895
1053
|
if (f.blendOptions && f.blendOptions.Opct) frame.opacity = parsePercent(f.blendOptions.Opct);
|
|
896
1054
|
target.animationFrames.push(frame);
|
|
897
1055
|
}
|
|
@@ -922,7 +1080,7 @@ addHandler(
|
|
|
922
1080
|
};
|
|
923
1081
|
|
|
924
1082
|
if (desc.trackList) {
|
|
925
|
-
timeline.tracks = parseTrackList(desc.trackList,
|
|
1083
|
+
timeline.tracks = parseTrackList(desc.trackList, reader);
|
|
926
1084
|
}
|
|
927
1085
|
|
|
928
1086
|
target.timeline = timeline;
|
|
@@ -994,7 +1152,7 @@ addHandler(
|
|
|
994
1152
|
frame.FrLs = f.frames;
|
|
995
1153
|
if (f.offset) frame.Ofst = xyToHorzVrtc(f.offset);
|
|
996
1154
|
if (f.referencePoint) frame.FXRf = xyToHorzVrtc(f.referencePoint);
|
|
997
|
-
if (f.effects) frame.Lefx = serializeEffects(f.effects,
|
|
1155
|
+
if (f.effects) frame.Lefx = serializeEffects(f.effects, writer, hasMultiEffects(f.effects));
|
|
998
1156
|
if (f.opacity !== undefined) frame.blendOptions = { Opct: unitsPercentF(f.opacity) };
|
|
999
1157
|
desc.LaSt.push(frame);
|
|
1000
1158
|
}
|
|
@@ -1038,7 +1196,7 @@ addHandler(
|
|
|
1038
1196
|
} as any;
|
|
1039
1197
|
|
|
1040
1198
|
if (timeline.tracks) {
|
|
1041
|
-
desc.trackList = serializeTrackList(timeline.tracks);
|
|
1199
|
+
desc.trackList = serializeTrackList(timeline.tracks, writer);
|
|
1042
1200
|
}
|
|
1043
1201
|
|
|
1044
1202
|
desc.LyrI = getLayerId(target, options);
|
|
@@ -2244,6 +2402,91 @@ function pointToHrznVrtc(point: { x: UnitsValue; y: UnitsValue; }): HrznVrtcDesc
|
|
|
2244
2402
|
};
|
|
2245
2403
|
}
|
|
2246
2404
|
|
|
2405
|
+
// Camera Raw Filter setting paths (in CameraRawFilterSettings) and their descriptor keys
|
|
2406
|
+
const cameraRawColorKeys: [keyof CameraRawColors, string][] = [
|
|
2407
|
+
['red', 'R'], ['orange', 'O'], ['yellow', 'Y'], ['green', 'G'], ['aqua', 'A'], ['blue', 'B'], ['purple', 'P'], ['magenta', 'M'],
|
|
2408
|
+
];
|
|
2409
|
+
|
|
2410
|
+
const cameraRawSettings: [string, string][] = [
|
|
2411
|
+
['version', 'CrVe'], ['processVersion', 'PrVN'], ['processVersionCode', 'PrVe'], ['whiteBalance', 'WBal'],
|
|
2412
|
+
['temperature', 'Temp'], ['tint', 'Tint'], ['exposure', 'Ex12'], ['contrast', 'Cr12'], ['highlights', 'Hi12'],
|
|
2413
|
+
['shadows', 'Sh12'], ['whites', 'Wh12'], ['blacks', 'Bk12'], ['texture', 'CrTx'], ['clarity', 'Cl12'],
|
|
2414
|
+
['dehaze', 'Dhze'], ['vibrance', 'Vibr'], ['saturation', 'Strt'],
|
|
2415
|
+
['parametricCurve.shadows', 'PC_S'], ['parametricCurve.darks', 'PC_D'], ['parametricCurve.lights', 'PC_L'],
|
|
2416
|
+
['parametricCurve.highlights', 'PC_H'], ['parametricCurve.shadowSplit', 'PC_1'], ['parametricCurve.midtoneSplit', 'PC_2'],
|
|
2417
|
+
['parametricCurve.highlightSplit', 'PC_3'],
|
|
2418
|
+
['pointCurve.composite', 'Crv '], ['pointCurve.red', 'CrvR'], ['pointCurve.green', 'CrvG'], ['pointCurve.blue', 'CrvB'],
|
|
2419
|
+
...cameraRawColorKeys.map(([name, key]) => [`hsl.hue.${name}`, `HA_${key}`] as [string, string]),
|
|
2420
|
+
...cameraRawColorKeys.map(([name, key]) => [`hsl.saturation.${name}`, `SA_${key}`] as [string, string]),
|
|
2421
|
+
...cameraRawColorKeys.map(([name, key]) => [`hsl.luminance.${name}`, `LA_${key}`] as [string, string]),
|
|
2422
|
+
['colorGrading.shadows.hue', 'STSH'], ['colorGrading.shadows.saturation', 'STSS'], ['colorGrading.shadows.luminance', 'CgSL'],
|
|
2423
|
+
['colorGrading.midtones.hue', 'CgMH'], ['colorGrading.midtones.saturation', 'CgMS'], ['colorGrading.midtones.luminance', 'CgML'],
|
|
2424
|
+
['colorGrading.highlights.hue', 'STHH'], ['colorGrading.highlights.saturation', 'STHS'], ['colorGrading.highlights.luminance', 'CgHL'],
|
|
2425
|
+
['colorGrading.global.hue', 'CgGH'], ['colorGrading.global.saturation', 'CgGS'], ['colorGrading.global.luminance', 'CgGL'],
|
|
2426
|
+
['colorGrading.blending', 'CgBl'], ['colorGrading.balance', 'STB '],
|
|
2427
|
+
['sharpening.amount', 'Shrp'], ['sharpening.radius', 'ShpR'], ['sharpening.detail', 'ShpD'], ['sharpening.masking', 'ShpM'],
|
|
2428
|
+
['noiseReduction.luminance', 'LNR '], ['noiseReduction.luminanceDetail', 'LNRD'], ['noiseReduction.luminanceContrast', 'LNRC'],
|
|
2429
|
+
['noiseReduction.color', 'CNR '], ['noiseReduction.colorDetail', 'CNRD'], ['noiseReduction.colorSmoothness', 'CNRS'],
|
|
2430
|
+
['grain.amount', 'GRNA'], ['grain.size', 'GRNS'], ['grain.roughness', 'GRNF'],
|
|
2431
|
+
['postCropVignette.amount', 'PCVA'], ['postCropVignette.midpoint', 'PCVM'], ['postCropVignette.feather', 'PCVF'],
|
|
2432
|
+
['postCropVignette.roundness', 'PCVR'],
|
|
2433
|
+
];
|
|
2434
|
+
|
|
2435
|
+
const cameraRawCurveKeys = ['Crv ', 'CrvR', 'CrvG', 'CrvB'];
|
|
2436
|
+
const cameraRawFilterID = 2783;
|
|
2437
|
+
|
|
2438
|
+
function parseCameraRawSettings(desc: any, reader: PsdReader) {
|
|
2439
|
+
const settings: any = {};
|
|
2440
|
+
|
|
2441
|
+
for (const [path, key] of cameraRawSettings) {
|
|
2442
|
+
let value = desc[key];
|
|
2443
|
+
if (value === undefined) continue;
|
|
2444
|
+
|
|
2445
|
+
if (key === 'WBal') {
|
|
2446
|
+
value = (value as string).split('.')[1];
|
|
2447
|
+
} else if (cameraRawCurveKeys.includes(key)) {
|
|
2448
|
+
const values = value as number[];
|
|
2449
|
+
value = [];
|
|
2450
|
+
for (let i = 0; i + 1 < values.length; i += 2) value.push({ input: values[i], output: values[i + 1] });
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
const parts = path.split('.');
|
|
2454
|
+
let target = settings;
|
|
2455
|
+
for (let i = 0; i < parts.length - 1; i++) target = target[parts[i]] = target[parts[i]] ?? {};
|
|
2456
|
+
target[parts[parts.length - 1]] = value;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
for (const key of Object.keys(desc)) {
|
|
2460
|
+
if (key !== '_name' && key !== '_classID' && !cameraRawSettings.some(s => s[1] === key)) {
|
|
2461
|
+
reader.logMissingFeatures && reader.log(`Unhandled Camera Raw Filter setting: ${key}`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
return settings as CameraRawFilterSettings;
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
function serializeCameraRawSettings(settings: CameraRawFilterSettings) {
|
|
2469
|
+
const desc: any = { _name: '', _classID: cameraRawFilterClassID };
|
|
2470
|
+
|
|
2471
|
+
for (const [path, key] of cameraRawSettings) {
|
|
2472
|
+
let value: any = settings;
|
|
2473
|
+
for (const part of path.split('.')) value = value?.[part];
|
|
2474
|
+
if (value === undefined) continue;
|
|
2475
|
+
|
|
2476
|
+
if (key === 'WBal') {
|
|
2477
|
+
value = `WBal.${value}`;
|
|
2478
|
+
} else if (cameraRawCurveKeys.includes(key)) {
|
|
2479
|
+
value = (value as CameraRawCurvePoint[]).flatMap(p => [Math.round(p.input), Math.round(p.output)]);
|
|
2480
|
+
} else if (typeof value === 'number' && key !== 'Ex12' && key !== 'ShpR') {
|
|
2481
|
+
value = Math.round(value);
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
desc[key] = value;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
return desc;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2247
2490
|
function parseFilterFXItem(f: SoLdDescriptorFilterItem, reader: PsdReader): Filter | undefined {
|
|
2248
2491
|
const base: Omit<Filter, 'type' | 'filter'> = {
|
|
2249
2492
|
name: f['Nm '],
|
|
@@ -2255,6 +2498,10 @@ function parseFilterFXItem(f: SoLdDescriptorFilterItem, reader: PsdReader): Filt
|
|
|
2255
2498
|
backgroundColor: parseColor(f.BckC),
|
|
2256
2499
|
};
|
|
2257
2500
|
|
|
2501
|
+
if ('Fltr' in f && (f.Fltr._classID as string) === cameraRawFilterClassID) {
|
|
2502
|
+
return { ...base, type: 'camera raw', filter: parseCameraRawSettings(f.Fltr, reader) };
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2258
2505
|
if ('Fltr' in f) {
|
|
2259
2506
|
switch (f.Fltr._classID) {
|
|
2260
2507
|
case 'boxblur': return {
|
|
@@ -3594,6 +3841,11 @@ function serializeFilterFXItem(f: Filter): SoLdDescriptorFilterItem {
|
|
|
3594
3841
|
},
|
|
3595
3842
|
filterID: 1282829427,
|
|
3596
3843
|
};
|
|
3844
|
+
case 'camera raw': return {
|
|
3845
|
+
...base,
|
|
3846
|
+
Fltr: serializeCameraRawSettings(f.filter),
|
|
3847
|
+
filterID: cameraRawFilterID,
|
|
3848
|
+
} as any;
|
|
3597
3849
|
case 'brightness/contrast': return {
|
|
3598
3850
|
...base,
|
|
3599
3851
|
Fltr: {
|
|
@@ -3914,36 +4166,24 @@ addHandler(
|
|
|
3914
4166
|
},
|
|
3915
4167
|
);
|
|
3916
4168
|
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
(
|
|
3922
|
-
|
|
3923
|
-
(
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
}
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
if (target.patterns === undefined) target.patterns = [];
|
|
3936
|
-
target.patterns.push(pattern);
|
|
3937
|
-
}
|
|
3938
|
-
},
|
|
3939
|
-
(writer, target, _, _options) => {
|
|
3940
|
-
const patterns = target.patterns || [];
|
|
3941
|
-
for (const pattern of patterns) {
|
|
3942
|
-
writePattern(writer, pattern);
|
|
3943
|
-
}
|
|
3944
|
-
},
|
|
3945
|
-
);
|
|
3946
|
-
}
|
|
4169
|
+
addHandler(
|
|
4170
|
+
'Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
|
|
4171
|
+
target => !!(target.patterns && target.patterns.length > 0),
|
|
4172
|
+
(reader, target, left) => {
|
|
4173
|
+
while (left() > 0) {
|
|
4174
|
+
const pattern = readPatternSafe(reader);
|
|
4175
|
+
if (!pattern) continue;
|
|
4176
|
+
if (target.patterns === undefined) target.patterns = [];
|
|
4177
|
+
target.patterns.push(pattern);
|
|
4178
|
+
}
|
|
4179
|
+
},
|
|
4180
|
+
(writer, target, _, _options) => {
|
|
4181
|
+
const patterns = target.patterns || [];
|
|
4182
|
+
for (const pattern of patterns) {
|
|
4183
|
+
writePattern(writer, pattern);
|
|
4184
|
+
}
|
|
4185
|
+
},
|
|
4186
|
+
);
|
|
3947
4187
|
|
|
3948
4188
|
addHandlerAlias('Pat2', 'Patt');
|
|
3949
4189
|
addHandlerAlias('Pat3', 'Patt');
|
|
@@ -4419,12 +4659,12 @@ addHandler(
|
|
|
4419
4659
|
if (version !== 0) throw new Error(`Invalid lfxs version`);
|
|
4420
4660
|
|
|
4421
4661
|
const desc: Lfx2Descriptor & LmfxDescriptor = readVersionAndDescriptor(reader);
|
|
4422
|
-
target.effects = parseEffects(desc,
|
|
4662
|
+
target.effects = parseEffects(desc, reader);
|
|
4423
4663
|
|
|
4424
4664
|
skipBytes(reader, left());
|
|
4425
4665
|
},
|
|
4426
|
-
(writer, target
|
|
4427
|
-
const desc = serializeEffects(target.effects!,
|
|
4666
|
+
(writer, target) => {
|
|
4667
|
+
const desc = serializeEffects(target.effects!, writer, true);
|
|
4428
4668
|
writeUint32(writer, 0); // version
|
|
4429
4669
|
writeVersionAndDescriptor(writer, '', 'null', desc);
|
|
4430
4670
|
},
|
|
@@ -4497,10 +4737,17 @@ addHandler(
|
|
|
4497
4737
|
}
|
|
4498
4738
|
|
|
4499
4739
|
if (left() >= 8) {
|
|
4500
|
-
|
|
4501
|
-
|
|
4740
|
+
const signature = readSignature(reader);
|
|
4741
|
+
let totalChannelRecords: number;
|
|
4502
4742
|
|
|
4503
|
-
|
|
4743
|
+
if (signature === 'ls\x00\x03') {
|
|
4744
|
+
// Clip Studio Paint writes 'ls' instead of 'Lvls' signature (version is part of the read signature)
|
|
4745
|
+
totalChannelRecords = readUint16(reader);
|
|
4746
|
+
} else {
|
|
4747
|
+
if (signature !== 'Lvls') throw new Error(`Invalid levl signature`);
|
|
4748
|
+
if (readUint16(reader) !== 3) throw new Error(`Invalid levl version`);
|
|
4749
|
+
totalChannelRecords = readUint16(reader);
|
|
4750
|
+
}
|
|
4504
4751
|
|
|
4505
4752
|
while (channels.length < totalChannelRecords && left() >= 10) {
|
|
4506
4753
|
channels.push(readLevelsChannel(reader));
|
|
@@ -4563,71 +4810,81 @@ addHandler(
|
|
|
4563
4810
|
'curv',
|
|
4564
4811
|
adjustmentType('curves'),
|
|
4565
4812
|
(reader, target, left) => {
|
|
4566
|
-
readUint8(reader);
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
const
|
|
4570
|
-
const channels: CurvesAdjustmentChannel[] = [];
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4813
|
+
const isMap = !!readUint8(reader); // curves drawn with pencil tool (lookup tables instead of points)
|
|
4814
|
+
const version = readUint16(reader);
|
|
4815
|
+
if (version !== 1 && version !== 4) throw new Error('Invalid curv version');
|
|
4816
|
+
const countOrMask = readUint32(reader);
|
|
4817
|
+
const channels: (CurvesAdjustmentChannel | number[])[] = [];
|
|
4818
|
+
const readChannel = () => isMap ? Array.from(readBytes(reader, 256)) : readCurveChannel(reader);
|
|
4819
|
+
|
|
4820
|
+
if (version === 1) {
|
|
4821
|
+
for (let i = 0; i < 32; i++) {
|
|
4822
|
+
if (countOrMask & (1 << i)) {
|
|
4823
|
+
while (channels.length < i) channels.push([]);
|
|
4824
|
+
channels.push(readChannel());
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
} else {
|
|
4828
|
+
if (countOrMask > 64) throw new Error('Invalid curv channel count');
|
|
4829
|
+
for (let i = 0; i < countOrMask; i++) channels.push(readChannel());
|
|
4830
|
+
}
|
|
4831
|
+
|
|
4832
|
+
// extra section stores curves for all channels (including ones that don't fit in the mask)
|
|
4833
|
+
if (version === 1 && left() >= 10 && readSignature(reader) === 'Crv ') {
|
|
4834
|
+
readUint16(reader); // version
|
|
4835
|
+
const count = readUint32(reader);
|
|
4836
|
+
|
|
4837
|
+
for (let i = 0; i < count && left() >= 2; i++) {
|
|
4838
|
+
const index = readUint16(reader);
|
|
4839
|
+
const channel = readChannel();
|
|
4840
|
+
while (channels.length < index) channels.push([]);
|
|
4841
|
+
channels[index] = channel;
|
|
4576
4842
|
}
|
|
4577
4843
|
}
|
|
4578
4844
|
|
|
4579
4845
|
target.adjustment = {
|
|
4580
4846
|
...target.adjustment as PresetInfo,
|
|
4581
4847
|
type: 'curves',
|
|
4582
|
-
channels,
|
|
4848
|
+
...(isMap ? { values: channels as number[][] } : { channels: channels as CurvesAdjustmentChannel[] }),
|
|
4583
4849
|
};
|
|
4584
4850
|
|
|
4585
|
-
// ignoring, duplicate information
|
|
4586
|
-
// checkSignature(reader, 'Crv ');
|
|
4587
|
-
|
|
4588
|
-
// const cVersion = readUint16(reader);
|
|
4589
|
-
// readUint16(reader);
|
|
4590
|
-
// const channelCount = readUint16(reader);
|
|
4591
|
-
|
|
4592
|
-
// for (let i = 0; i < channelCount; i++) {
|
|
4593
|
-
// const index = readUint16(reader);
|
|
4594
|
-
// const nodes = readUint16(reader);
|
|
4595
|
-
|
|
4596
|
-
// for (let j = 0; j < nodes; j++) {
|
|
4597
|
-
// const output = readInt16(reader);
|
|
4598
|
-
// const input = readInt16(reader);
|
|
4599
|
-
// }
|
|
4600
|
-
// }
|
|
4601
|
-
|
|
4602
4851
|
skipBytes(reader, left());
|
|
4603
4852
|
},
|
|
4604
4853
|
(writer, target) => {
|
|
4605
|
-
const
|
|
4854
|
+
const adjustment = target.adjustment as CurvesAdjustment;
|
|
4855
|
+
const isMap = !!adjustment.values;
|
|
4856
|
+
const channels: (CurvesAdjustmentChannel | number[])[] = (isMap ? adjustment.values : adjustment.channels) || [];
|
|
4606
4857
|
const used: number[] = [];
|
|
4607
4858
|
let channelsMask = 0;
|
|
4608
4859
|
|
|
4609
4860
|
for (let i = 0; i < channels.length; i++) {
|
|
4610
4861
|
if (channels[i]?.length) {
|
|
4611
|
-
channelsMask |= 1 << i;
|
|
4862
|
+
if (i < 32) channelsMask |= 1 << i;
|
|
4612
4863
|
used.push(i);
|
|
4613
4864
|
}
|
|
4614
4865
|
}
|
|
4615
4866
|
|
|
4616
|
-
|
|
4867
|
+
const writeChannel = (channel: CurvesAdjustmentChannel | number[]) => {
|
|
4868
|
+
if (isMap) {
|
|
4869
|
+
for (let i = 0; i < 256; i++) writeUint8(writer, clamp(Math.round((channel as number[])[i] ?? i), 0, 255));
|
|
4870
|
+
} else {
|
|
4871
|
+
writeCurveChannel(writer, channel as CurvesAdjustmentChannel);
|
|
4872
|
+
}
|
|
4873
|
+
};
|
|
4874
|
+
|
|
4875
|
+
writeUint8(writer, isMap ? 1 : 0);
|
|
4617
4876
|
writeUint16(writer, 1); // version
|
|
4618
|
-
|
|
4619
|
-
writeUint16(writer, channelsMask);
|
|
4877
|
+
writeUint32(writer, channelsMask >>> 0);
|
|
4620
4878
|
|
|
4621
|
-
for (const i of used)
|
|
4879
|
+
for (const i of used) if (i < 32) writeChannel(channels[i]);
|
|
4622
4880
|
|
|
4623
4881
|
writeSignature(writer, 'Crv ');
|
|
4624
4882
|
writeUint16(writer, 4); // version
|
|
4625
|
-
|
|
4626
|
-
writeUint16(writer, used.length);
|
|
4883
|
+
writeUint32(writer, used.length);
|
|
4627
4884
|
|
|
4628
4885
|
for (const i of used) {
|
|
4629
4886
|
writeUint16(writer, i);
|
|
4630
|
-
|
|
4887
|
+
writeChannel(channels[i]);
|
|
4631
4888
|
}
|
|
4632
4889
|
},
|
|
4633
4890
|
);
|
|
@@ -5567,6 +5824,10 @@ addHandler(
|
|
|
5567
5824
|
);
|
|
5568
5825
|
|
|
5569
5826
|
addHandlerAlias('FXid', 'FEid');
|
|
5827
|
+
addHandlerAlias('FELS', 'FEid'); // filter effects 3
|
|
5828
|
+
addHandlerAlias('hue ', 'hue2'); // old hue/saturation (Photoshop 4.0), same structure as 'hue2'
|
|
5829
|
+
addHandlerAlias('plLd', 'PlLd'); // old placed layer key
|
|
5830
|
+
addHandlerAlias('abdd', 'artb'); // artboard data 3
|
|
5570
5831
|
|
|
5571
5832
|
addHandler(
|
|
5572
5833
|
'FMsk',
|
|
@@ -5648,12 +5909,12 @@ addHandler(
|
|
|
5648
5909
|
// console.log('READ', require('util').inspect(desc, false, 99, true));
|
|
5649
5910
|
|
|
5650
5911
|
// discard if read in 'lrFX' section ('lmfx' and 'lfx2' are never stored together)
|
|
5651
|
-
target.effects = parseEffects(desc,
|
|
5912
|
+
target.effects = parseEffects(desc, reader);
|
|
5652
5913
|
|
|
5653
5914
|
skipBytes(reader, left());
|
|
5654
5915
|
},
|
|
5655
|
-
(writer, target
|
|
5656
|
-
const desc = serializeEffects(target.effects!,
|
|
5916
|
+
(writer, target) => {
|
|
5917
|
+
const desc = serializeEffects(target.effects!, writer, true);
|
|
5657
5918
|
// console.log('WRITE', require('util').inspect(desc, false, 99, true));
|
|
5658
5919
|
|
|
5659
5920
|
writeUint32(writer, 0); // version
|
|
@@ -5735,6 +5996,91 @@ addHandler(
|
|
|
5735
5996
|
},
|
|
5736
5997
|
);
|
|
5737
5998
|
|
|
5999
|
+
// generator settings stored by older versions of Photoshop (written back in 'shmd' or 'extn' section)
|
|
6000
|
+
addHandler(
|
|
6001
|
+
'extd',
|
|
6002
|
+
() => false,
|
|
6003
|
+
(reader, target, left) => {
|
|
6004
|
+
const desc = readVersionAndDescriptor(reader) as GeneratorSettingsDescriptor;
|
|
6005
|
+
if (desc.generatorSettings && target.generatorSettings === undefined) {
|
|
6006
|
+
target.generatorSettings = parseGeneratorSettings(desc.generatorSettings);
|
|
6007
|
+
}
|
|
6008
|
+
skipBytes(reader, left());
|
|
6009
|
+
},
|
|
6010
|
+
() => { },
|
|
6011
|
+
);
|
|
6012
|
+
|
|
6013
|
+
interface FrgbDescriptor {
|
|
6014
|
+
framedGroupRect: { _name: ''; _classID: 'classFloatRect'; 'Top ': number; Left: number; Btom: number; Rght: number; };
|
|
6015
|
+
framedGroupType: number;
|
|
6016
|
+
LockPPI?: boolean;
|
|
6017
|
+
PreferredResolution?: number;
|
|
6018
|
+
SavedIteratedName?: string;
|
|
6019
|
+
}
|
|
6020
|
+
|
|
6021
|
+
addHandler(
|
|
6022
|
+
'frgb', // frame tool group
|
|
6023
|
+
hasKey('framedGroup'),
|
|
6024
|
+
(reader, target, left) => {
|
|
6025
|
+
const desc = readVersionAndDescriptor(reader) as FrgbDescriptor;
|
|
6026
|
+
const rect = desc.framedGroupRect;
|
|
6027
|
+
target.framedGroup = {
|
|
6028
|
+
rect: { top: rect['Top '], left: rect.Left, bottom: rect.Btom, right: rect.Rght },
|
|
6029
|
+
type: desc.framedGroupType,
|
|
6030
|
+
};
|
|
6031
|
+
if (desc.LockPPI !== undefined) target.framedGroup.lockPPI = desc.LockPPI;
|
|
6032
|
+
if (desc.PreferredResolution !== undefined) target.framedGroup.preferredResolution = desc.PreferredResolution;
|
|
6033
|
+
if (desc.SavedIteratedName !== undefined) target.framedGroup.savedIteratedName = desc.SavedIteratedName;
|
|
6034
|
+
skipBytes(reader, left());
|
|
6035
|
+
},
|
|
6036
|
+
(writer, target) => {
|
|
6037
|
+
const group = target.framedGroup!;
|
|
6038
|
+
const rect = group.rect;
|
|
6039
|
+
const desc: FrgbDescriptor = {
|
|
6040
|
+
framedGroupRect: { _name: '', _classID: 'classFloatRect', 'Top ': rect.top, Left: rect.left, Btom: rect.bottom, Rght: rect.right },
|
|
6041
|
+
framedGroupType: group.type,
|
|
6042
|
+
};
|
|
6043
|
+
if (group.lockPPI !== undefined) desc.LockPPI = group.lockPPI;
|
|
6044
|
+
if (group.preferredResolution !== undefined) desc.PreferredResolution = group.preferredResolution;
|
|
6045
|
+
if (group.savedIteratedName !== undefined) desc.SavedIteratedName = group.savedIteratedName;
|
|
6046
|
+
writeVersionAndDescriptor(writer, '', 'framedGroup', desc);
|
|
6047
|
+
},
|
|
6048
|
+
);
|
|
6049
|
+
|
|
6050
|
+
addHandler(
|
|
6051
|
+
'anFX',
|
|
6052
|
+
hasKey('animationEffects'),
|
|
6053
|
+
(reader, target, left) => {
|
|
6054
|
+
target.animationEffects = readBytes(reader, left());
|
|
6055
|
+
},
|
|
6056
|
+
(writer, target) => {
|
|
6057
|
+
writeBytes(writer, target.animationEffects);
|
|
6058
|
+
},
|
|
6059
|
+
);
|
|
6060
|
+
|
|
6061
|
+
addHandler(
|
|
6062
|
+
'PxSD', // pixel source data 2 (video layer frames)
|
|
6063
|
+
hasKey('pixelSourceData'),
|
|
6064
|
+
(reader, target, left) => {
|
|
6065
|
+
target.pixelSourceData = [];
|
|
6066
|
+
|
|
6067
|
+
while (left() >= 8) {
|
|
6068
|
+
const length = readLength64(reader);
|
|
6069
|
+
if (length > left()) throw new Error('Invalid PxSD data length');
|
|
6070
|
+
target.pixelSourceData.push(readBytes(reader, length));
|
|
6071
|
+
}
|
|
6072
|
+
|
|
6073
|
+
skipBytes(reader, left());
|
|
6074
|
+
},
|
|
6075
|
+
(writer, target) => {
|
|
6076
|
+
for (const data of target.pixelSourceData!) {
|
|
6077
|
+
writeUint32(writer, 0);
|
|
6078
|
+
writeUint32(writer, data.byteLength);
|
|
6079
|
+
writeBytes(writer, data);
|
|
6080
|
+
}
|
|
6081
|
+
},
|
|
6082
|
+
);
|
|
6083
|
+
|
|
5738
6084
|
addHandler(
|
|
5739
6085
|
'iOpa',
|
|
5740
6086
|
hasKey('fillOpacity'),
|