ag-psd 31.0.3 → 33.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/00d0e0b4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/0cc76730 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/20729831 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/214a593b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/25f8b84a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/27518289 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/330ef2d9 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/37ff16b8 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/3f72a97c +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/75efccd4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/762f9305 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7bcfc50a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/825e9a05 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87372817 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/891a7c73 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/8b68a3a2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a1d12a93 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a7e80865 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/ac317c9c +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/b8569d6b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b8b073c4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/bb489c89 +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/c46725e1 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c794cb34 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cd4ae980 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/d02dd6f7 +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/e6735171 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f5417276 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f74d3518 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f886deac +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fd0a2987 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fe349423 +0 -0
- package/CHANGELOG.md +107 -0
- package/LICENSE +5 -0
- package/README.md +3 -6
- package/README_PSD.md +242 -81
- package/dist/abr.d.ts +11 -4
- package/dist/abr.js +363 -229
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +56 -2
- package/dist/additionalInfo.js +600 -364
- package/dist/additionalInfo.js.map +1 -1
- package/dist/ase.d.ts +6 -1
- package/dist/ase.js +61 -61
- package/dist/ase.js.map +1 -1
- package/dist/bundle.js +3096 -1541
- package/dist/descriptor.d.ts +25 -6
- package/dist/descriptor.js +380 -135
- package/dist/descriptor.js.map +1 -1
- package/dist/effectsHelpers.js +12 -12
- package/dist/effectsHelpers.js.map +1 -1
- package/dist/engineData.d.ts +3 -1
- package/dist/engineData.js +34 -13
- package/dist/engineData.js.map +1 -1
- package/dist/engineData2.js +50 -21
- package/dist/engineData2.js.map +1 -1
- package/dist/helpers.d.ts +6 -3
- package/dist/helpers.js +22 -6
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.d.ts +15 -3
- package/dist/imageResources.js +529 -144
- package/dist/imageResources.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jpeg.js +30 -10
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +154 -18
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.d.ts +12 -2
- package/dist/psdReader.js +720 -421
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +3 -0
- package/dist/psdWriter.js +167 -130
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.js +143 -29
- package/dist/text.js.map +1 -1
- package/dist/utf8.js +36 -18
- package/dist/utf8.js.map +1 -1
- package/dist-es/abr.d.ts +11 -4
- package/dist-es/abr.js +363 -229
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +56 -2
- package/dist-es/additionalInfo.js +600 -364
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/ase.d.ts +6 -1
- package/dist-es/ase.js +61 -61
- package/dist-es/ase.js.map +1 -1
- package/dist-es/descriptor.d.ts +25 -6
- package/dist-es/descriptor.js +380 -135
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/effectsHelpers.js +12 -12
- package/dist-es/effectsHelpers.js.map +1 -1
- package/dist-es/engineData.d.ts +3 -1
- package/dist-es/engineData.js +34 -13
- package/dist-es/engineData.js.map +1 -1
- package/dist-es/engineData2.js +50 -21
- package/dist-es/engineData2.js.map +1 -1
- package/dist-es/helpers.d.ts +6 -3
- package/dist-es/helpers.js +22 -6
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.d.ts +15 -3
- package/dist-es/imageResources.js +529 -144
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/index.js +1 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/jpeg.js +30 -10
- package/dist-es/jpeg.js.map +1 -1
- package/dist-es/psd.d.ts +154 -18
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.d.ts +12 -2
- package/dist-es/psdReader.js +720 -421
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +3 -0
- package/dist-es/psdWriter.js +167 -130
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.js +143 -29
- package/dist-es/text.js.map +1 -1
- package/dist-es/utf8.js +36 -18
- package/dist-es/utf8.js.map +1 -1
- package/package.json +2 -2
- package/src/abr.ts +380 -232
- package/src/additionalInfo.ts +781 -477
- package/src/ase.ts +66 -61
- package/src/descriptor.ts +386 -142
- package/src/effectsHelpers.ts +9 -9
- package/src/engineData.ts +36 -13
- package/src/engineData2.ts +468 -432
- package/src/helpers.ts +23 -5
- package/src/imageResources.ts +658 -167
- package/src/index.ts +1 -0
- package/src/jpeg.ts +27 -12
- package/src/psd.ts +158 -30
- package/src/psdReader.ts +732 -414
- package/src/psdWriter.ts +186 -132
- package/src/text.ts +139 -18
- package/src/utf8.ts +35 -21
package/src/imageResources.ts
CHANGED
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
import { toByteArray } from 'base64-js';
|
|
2
|
-
import { BlendMode, ImageResources, RenderingIntent } from './psd';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { BlendMode, HalftoneScreen, ImageResources, KeyDescriptorItem, PrintTransferFunction, RenderingIntent, SavedPath } from './psd';
|
|
3
|
+
import { KeyDescriptorListDescriptor, parseKeyDescriptorList, readVectorMask, serializeKeyDescriptorList, writeVectorMask } from './additionalInfo';
|
|
4
|
+
import { PsdReader, readUnicodeString, readUint32, readUint16, readUint8, readFloat64, readBytes, skipBytes, readFloat32, readInt16, readFixedPoint32, readSignature, checkSignature, readSection, readColor, readInt32, readAsciiString, decodeUtf8, getUtf8StrictDecoder, getGbkStrictDecoder } from './psdReader';
|
|
5
|
+
import { PsdWriter, writeUnicodeString, writeUint32, writeUint8, writeFloat64, writeUint16, writeBytes, writeInt16, writeFloat32, writeFixedPoint32, writeUnicodeStringWithPadding, writeColor, writeSignature, writeSection, writeInt32, writeAsciiString, writeZeros } from './psdWriter';
|
|
6
|
+
import { clamp, ColorSpace, createCanvasFromData, createEnum, createImageData, imageDataToCanvas, MOCK_HANDLERS } from './helpers';
|
|
7
|
+
import { encodeString } from './utf8';
|
|
8
|
+
import { ESliceBGColorType, ESliceHorzAlign, ESliceOrigin, ESliceType, ESliceVertAlign, frac, FractionDescriptor, parseTrackList, pathSelectionStateToReference, DescriptorReferenceItem, readVersionAndDescriptor, serializeTrackList, TimelineTrackDescriptor, TimeScopeDescriptor, writeVersionAndDescriptor, DescriptorColor, DescriptorUnitsValue, parseColor, serializeColor, parseUnits, unitsValue, parsePercent, unitsPercentF , outputSettingsRoot } from './descriptor';
|
|
8
9
|
|
|
9
10
|
export interface InternalImageResources extends ImageResources {
|
|
10
11
|
layersGroup?: number[];
|
|
11
12
|
layerGroupsEnabledId?: number[];
|
|
13
|
+
savedPathsOrigination?: KeyDescriptorItem[][];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ResourceDocumentInfo {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ResourceInfo extends ResourceDocumentInfo {
|
|
22
|
+
signature: string; // '8BIM', or 'MeSa' etc. for resources from other applications
|
|
23
|
+
id: number;
|
|
24
|
+
name: Uint8Array; // raw pascal string bytes
|
|
12
25
|
}
|
|
13
26
|
|
|
14
27
|
export interface ResourceHandler {
|
|
15
28
|
key: number;
|
|
29
|
+
keyCount: number; // number of consecutive resource ids handled, starting at `key` (index is added to `key` when writing)
|
|
16
30
|
has: (target: InternalImageResources) => boolean | number;
|
|
17
|
-
read: (reader: PsdReader, target: InternalImageResources, left: () => number) => void;
|
|
18
|
-
write: (writer: PsdWriter, target: InternalImageResources, index: number) => void;
|
|
31
|
+
read: (reader: PsdReader, target: InternalImageResources, left: () => number, info: ResourceInfo) => void;
|
|
32
|
+
write: (writer: PsdWriter, target: InternalImageResources, index: number, document: ResourceDocumentInfo) => void;
|
|
33
|
+
name?: (target: InternalImageResources, index: number) => string;
|
|
19
34
|
}
|
|
20
35
|
|
|
21
36
|
export const resourceHandlers: ResourceHandler[] = [];
|
|
@@ -24,12 +39,13 @@ export const resourceHandlersMap: { [key: number]: ResourceHandler } = {};
|
|
|
24
39
|
function addHandler(
|
|
25
40
|
key: number,
|
|
26
41
|
has: (target: InternalImageResources) => boolean | number,
|
|
27
|
-
read: (reader: PsdReader, target: InternalImageResources, left: () => number) => void,
|
|
28
|
-
write: (writer: PsdWriter, target: InternalImageResources, index: number) => void,
|
|
42
|
+
read: (reader: PsdReader, target: InternalImageResources, left: () => number, info: ResourceInfo) => void,
|
|
43
|
+
write: (writer: PsdWriter, target: InternalImageResources, index: number, document: ResourceDocumentInfo) => void,
|
|
44
|
+
options: { keyCount?: number; name?: (target: InternalImageResources, index: number) => string; } = {},
|
|
29
45
|
) {
|
|
30
|
-
const handler: ResourceHandler = { key, has, read, write };
|
|
46
|
+
const handler: ResourceHandler = { key, keyCount: options.keyCount ?? 1, has, read, write, name: options.name };
|
|
31
47
|
resourceHandlers.push(handler);
|
|
32
|
-
resourceHandlersMap[handler.key] = handler;
|
|
48
|
+
for (let i = 0; i < handler.keyCount; i++) resourceHandlersMap[handler.key + i] = handler;
|
|
33
49
|
}
|
|
34
50
|
|
|
35
51
|
const LOG_MOCK_HANDLERS = false;
|
|
@@ -49,7 +65,7 @@ function byteAt(value: string, index: number) {
|
|
|
49
65
|
|
|
50
66
|
function readUtf8String(reader: PsdReader, length: number) {
|
|
51
67
|
const buffer = readBytes(reader, length);
|
|
52
|
-
return
|
|
68
|
+
return decodeUtf8(reader, buffer);
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
function writeUtf8String(writer: PsdWriter, value: string) {
|
|
@@ -60,7 +76,10 @@ function writeUtf8String(writer: PsdWriter, value: string) {
|
|
|
60
76
|
function readEncodedString(reader: PsdReader) {
|
|
61
77
|
const length = readUint8(reader);
|
|
62
78
|
const buffer = readBytes(reader, length);
|
|
79
|
+
return decodeEncodedString(reader, buffer);
|
|
80
|
+
}
|
|
63
81
|
|
|
82
|
+
function decodeEncodedString(reader: PsdReader, buffer: Uint8Array) {
|
|
64
83
|
let notAscii = false;
|
|
65
84
|
for (let i = 0; i < buffer.byteLength; i++) {
|
|
66
85
|
if (buffer[i] & 0x80) {
|
|
@@ -70,36 +89,47 @@ function readEncodedString(reader: PsdReader) {
|
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
if (notAscii) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
// encoding is ambiguous, many GBK strings are also valid UTF-8 and vice versa, GBK is preferred,
|
|
93
|
+
// UTF-8 is only used if the string is not valid GBK
|
|
94
|
+
for (const decoder of [getGbkStrictDecoder(reader), getUtf8StrictDecoder(reader)]) {
|
|
95
|
+
if (decoder) {
|
|
96
|
+
try {
|
|
97
|
+
return decoder.decode(buffer);
|
|
98
|
+
} catch { }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
77
101
|
}
|
|
78
102
|
|
|
79
|
-
return
|
|
103
|
+
return decodeUtf8(reader, buffer);
|
|
80
104
|
}
|
|
81
105
|
|
|
82
|
-
function
|
|
106
|
+
function toShortAsciiString(value: string) {
|
|
83
107
|
let ascii = '';
|
|
84
108
|
|
|
85
|
-
for (let i = 0
|
|
86
|
-
|
|
109
|
+
for (let i = 0; i < value.length;) {
|
|
110
|
+
const code = value.codePointAt(i)!;
|
|
111
|
+
ascii += code > 0x7f ? '?' : String.fromCharCode(code);
|
|
112
|
+
i += code > 0xffff ? 2 : 1; // skip low surrogate of astral characters
|
|
87
113
|
}
|
|
88
114
|
|
|
89
|
-
|
|
115
|
+
// length is stored in a single byte
|
|
116
|
+
return ascii.length > 255 ? ascii.substring(0, 255) : ascii;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function writeEncodedString(writer: PsdWriter, value: string) {
|
|
120
|
+
const buffer = encodeString(toShortAsciiString(value));
|
|
90
121
|
writeUint8(writer, buffer.byteLength);
|
|
91
122
|
writeBytes(writer, buffer);
|
|
92
123
|
}
|
|
93
124
|
|
|
94
|
-
|
|
125
|
+
addHandler(
|
|
95
126
|
1028, // IPTC-NAA record
|
|
96
|
-
target =>
|
|
127
|
+
target => target.iptcData !== undefined,
|
|
97
128
|
(reader, target, left) => {
|
|
98
|
-
|
|
99
|
-
(target as any)._ir1028 = readBytes(reader, left());
|
|
129
|
+
target.iptcData = readBytes(reader, left());
|
|
100
130
|
},
|
|
101
131
|
(writer, target) => {
|
|
102
|
-
writeBytes(writer,
|
|
132
|
+
writeBytes(writer, target.iptcData!);
|
|
103
133
|
},
|
|
104
134
|
);
|
|
105
135
|
|
|
@@ -161,14 +191,14 @@ interface PrintInformationDescriptor {
|
|
|
161
191
|
};
|
|
162
192
|
}
|
|
163
193
|
|
|
164
|
-
|
|
194
|
+
addHandler(
|
|
165
195
|
1085, // Windows DEVMODE. Variable OS specific info for Windows.
|
|
166
|
-
target =>
|
|
196
|
+
target => target.windowsDevMode !== undefined,
|
|
167
197
|
(reader, target, left) => {
|
|
168
|
-
|
|
198
|
+
target.windowsDevMode = readBytes(reader, left());
|
|
169
199
|
},
|
|
170
200
|
(writer, target) => {
|
|
171
|
-
writeBytes(writer,
|
|
201
|
+
writeBytes(writer, target.windowsDevMode!);
|
|
172
202
|
}
|
|
173
203
|
);
|
|
174
204
|
|
|
@@ -186,6 +216,7 @@ addHandler(
|
|
|
186
216
|
const info = target.printInformation;
|
|
187
217
|
|
|
188
218
|
if (desc.PstS !== undefined) info.printerManagesColors = desc.PstS;
|
|
219
|
+
if (desc.ClrS === 'ClrS.Grys') info.printerProfileColorSpace = 'grayscale';
|
|
189
220
|
if (desc['Nm '] !== undefined) info.printerProfile = desc['Nm '];
|
|
190
221
|
if (desc.MpBl !== undefined) info.blackPointCompensation = desc.MpBl;
|
|
191
222
|
if (desc.printSixteenBit !== undefined) info.printSixteenBit = desc.printSixteenBit;
|
|
@@ -211,13 +242,13 @@ addHandler(
|
|
|
211
242
|
desc.PstS = true;
|
|
212
243
|
} else {
|
|
213
244
|
if (info.hardProof !== undefined) desc.hardProof = !!info.hardProof;
|
|
214
|
-
desc.ClrS = 'ClrS.
|
|
215
|
-
desc['Nm '] = info.printerProfile
|
|
245
|
+
desc.ClrS = info.printerProfileColorSpace === 'grayscale' ? 'ClrS.Grys' : 'ClrS.RGBC';
|
|
246
|
+
if (info.printerProfile !== undefined) desc['Nm '] = info.printerProfile;
|
|
216
247
|
}
|
|
217
248
|
|
|
218
249
|
desc.Inte = Inte.encode(info.renderingIntent);
|
|
219
250
|
|
|
220
|
-
if (!info.printerManagesColors) desc.MpBl = !!info.blackPointCompensation;
|
|
251
|
+
if (!info.printerManagesColors && info.blackPointCompensation !== undefined) desc.MpBl = !!info.blackPointCompensation;
|
|
221
252
|
|
|
222
253
|
desc.printSixteenBit = !!info.printSixteenBit;
|
|
223
254
|
desc.printerName = info.printerName || '';
|
|
@@ -229,9 +260,9 @@ addHandler(
|
|
|
229
260
|
MpBl: !!info.proofSetup.blackPointCompensation,
|
|
230
261
|
paperWhite: !!info.proofSetup.paperWhite,
|
|
231
262
|
};
|
|
232
|
-
} else {
|
|
263
|
+
} else if (info.proofSetup) {
|
|
233
264
|
desc.printProofSetup = {
|
|
234
|
-
Bltn:
|
|
265
|
+
Bltn: `builtinProof.${info.proofSetup.builtin || 'proofCMYK'}`,
|
|
235
266
|
};
|
|
236
267
|
}
|
|
237
268
|
|
|
@@ -239,19 +270,101 @@ addHandler(
|
|
|
239
270
|
},
|
|
240
271
|
);
|
|
241
272
|
|
|
242
|
-
|
|
273
|
+
interface PrintStyleDescriptor {
|
|
274
|
+
Cptn: boolean;
|
|
275
|
+
Clbr: boolean;
|
|
276
|
+
RgsM: boolean;
|
|
277
|
+
CrnC: boolean;
|
|
278
|
+
CntC: boolean;
|
|
279
|
+
Lbls: boolean;
|
|
280
|
+
Ngtv: boolean;
|
|
281
|
+
EmlD: boolean;
|
|
282
|
+
Intr: boolean;
|
|
283
|
+
Bckg: DescriptorColor;
|
|
284
|
+
BrdT: DescriptorUnitsValue;
|
|
285
|
+
'Bld ': DescriptorUnitsValue;
|
|
286
|
+
Rslt: DescriptorUnitsValue;
|
|
287
|
+
vectorData: boolean;
|
|
288
|
+
PgPs: string;
|
|
289
|
+
Left: DescriptorUnitsValue;
|
|
290
|
+
'Top ': DescriptorUnitsValue;
|
|
291
|
+
'Scl ': DescriptorUnitsValue;
|
|
292
|
+
cropWhenPrinting?: boolean;
|
|
293
|
+
cropRectBottom?: number;
|
|
294
|
+
cropRectLeft?: number;
|
|
295
|
+
cropRectRight?: number;
|
|
296
|
+
cropRectTop?: number;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
addHandler(
|
|
243
300
|
1083, // Print style
|
|
244
|
-
target =>
|
|
245
|
-
(reader, target
|
|
246
|
-
|
|
247
|
-
|
|
301
|
+
target => target.printStyle !== undefined,
|
|
302
|
+
(reader, target) => {
|
|
303
|
+
const desc: PrintStyleDescriptor = readVersionAndDescriptor(reader);
|
|
304
|
+
|
|
305
|
+
target.printStyle = {
|
|
306
|
+
caption: desc.Cptn,
|
|
307
|
+
calibrationBars: desc.Clbr,
|
|
308
|
+
registrationMarks: desc.RgsM,
|
|
309
|
+
cornerCropMarks: desc.CrnC,
|
|
310
|
+
centerCropMarks: desc.CntC,
|
|
311
|
+
labels: desc.Lbls,
|
|
312
|
+
negative: desc.Ngtv,
|
|
313
|
+
emulsionDown: desc.EmlD,
|
|
314
|
+
interpolate: desc.Intr,
|
|
315
|
+
backgroundColor: parseColor(desc.Bckg),
|
|
316
|
+
border: parseUnits(desc.BrdT),
|
|
317
|
+
bleed: parseUnits(desc['Bld ']),
|
|
318
|
+
resolution: parseUnits(desc.Rslt),
|
|
319
|
+
vectorData: desc.vectorData,
|
|
320
|
+
pagePosition: desc.PgPs === 'PgPs.PgPC' ? 'centered' : desc.PgPs,
|
|
321
|
+
left: parseUnits(desc.Left),
|
|
322
|
+
top: parseUnits(desc['Top ']),
|
|
323
|
+
scale: parsePercent(desc['Scl ']),
|
|
324
|
+
};
|
|
248
325
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
326
|
+
if (desc.cropWhenPrinting !== undefined) {
|
|
327
|
+
target.printStyle.cropWhenPrinting = desc.cropWhenPrinting;
|
|
328
|
+
target.printStyle.cropRect = {
|
|
329
|
+
top: desc.cropRectTop || 0,
|
|
330
|
+
left: desc.cropRectLeft || 0,
|
|
331
|
+
bottom: desc.cropRectBottom || 0,
|
|
332
|
+
right: desc.cropRectRight || 0,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
252
335
|
},
|
|
253
336
|
(writer, target) => {
|
|
254
|
-
|
|
337
|
+
const style = target.printStyle!;
|
|
338
|
+
const desc: PrintStyleDescriptor = {
|
|
339
|
+
Cptn: !!style.caption,
|
|
340
|
+
Clbr: !!style.calibrationBars,
|
|
341
|
+
RgsM: !!style.registrationMarks,
|
|
342
|
+
CrnC: !!style.cornerCropMarks,
|
|
343
|
+
CntC: !!style.centerCropMarks,
|
|
344
|
+
Lbls: !!style.labels,
|
|
345
|
+
Ngtv: !!style.negative,
|
|
346
|
+
EmlD: !!style.emulsionDown,
|
|
347
|
+
Intr: !!style.interpolate,
|
|
348
|
+
Bckg: serializeColor(style.backgroundColor || { r: 255, g: 255, b: 255 }),
|
|
349
|
+
BrdT: unitsValue(style.border || { units: 'Distance', value: 0 }, 'border'),
|
|
350
|
+
'Bld ': unitsValue(style.bleed || { units: 'Distance', value: 0 }, 'bleed'),
|
|
351
|
+
Rslt: unitsValue(style.resolution || { units: 'Pixels', value: 72 }, 'resolution'),
|
|
352
|
+
vectorData: style.vectorData ?? true,
|
|
353
|
+
PgPs: (!style.pagePosition || style.pagePosition === 'centered') ? 'PgPs.PgPC' : style.pagePosition,
|
|
354
|
+
Left: unitsValue(style.left || { units: 'Distance', value: 0 }, 'left'),
|
|
355
|
+
'Top ': unitsValue(style.top || { units: 'Distance', value: 0 }, 'top'),
|
|
356
|
+
'Scl ': unitsPercentF(style.scale ?? 1),
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
if (style.cropWhenPrinting !== undefined || style.cropRect) {
|
|
360
|
+
desc.cropWhenPrinting = !!style.cropWhenPrinting;
|
|
361
|
+
desc.cropRectBottom = style.cropRect?.bottom ?? 0;
|
|
362
|
+
desc.cropRectLeft = style.cropRect?.left ?? 0;
|
|
363
|
+
desc.cropRectRight = style.cropRect?.right ?? 0;
|
|
364
|
+
desc.cropRectTop = style.cropRect?.top ?? 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
writeVersionAndDescriptor(writer, '', 'printOutputOptions', desc);
|
|
255
368
|
},
|
|
256
369
|
);
|
|
257
370
|
|
|
@@ -350,15 +463,72 @@ addHandler(
|
|
|
350
463
|
},
|
|
351
464
|
);
|
|
352
465
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
466
|
+
const displayInfoKinds = ['selected', 'protected', 'spot'] as const;
|
|
467
|
+
const supportedColorSpaces: number[] = [ColorSpace.RGB, ColorSpace.HSB, ColorSpace.CMYK, ColorSpace.Lab, ColorSpace.Grayscale];
|
|
468
|
+
|
|
469
|
+
function readDisplayInfo(reader: PsdReader) {
|
|
470
|
+
const info: NonNullable<ImageResources['alphaChannelDisplayInfo']>[number] = { opacity: 0, kind: 'selected' };
|
|
471
|
+
const colorSpace = reader.view.getUint16(reader.offset);
|
|
472
|
+
|
|
473
|
+
if (supportedColorSpaces.indexOf(colorSpace) !== -1) {
|
|
474
|
+
info.color = readColor(reader);
|
|
475
|
+
} else {
|
|
476
|
+
// keep color in unknown color space as it is, so the channel info is not lost or misaligned
|
|
477
|
+
skipBytes(reader, 2);
|
|
478
|
+
info.rawColor = { colorSpace, values: [readUint16(reader), readUint16(reader), readUint16(reader), readUint16(reader)] };
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
info.opacity = readUint16(reader) / 100;
|
|
482
|
+
const kind = displayInfoKinds[readUint8(reader)];
|
|
483
|
+
if (!kind) throw new Error('Invalid display info kind');
|
|
484
|
+
info.kind = kind;
|
|
485
|
+
return info;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
addHandler(
|
|
489
|
+
1007, // Display info (obsolete, replaced by 1077), written back as 1077
|
|
490
|
+
() => false,
|
|
491
|
+
(reader, target, left) => {
|
|
492
|
+
const info: NonNullable<ImageResources['alphaChannelDisplayInfo']> = [];
|
|
493
|
+
|
|
494
|
+
while (left() >= 14) {
|
|
495
|
+
info.push(readDisplayInfo(reader));
|
|
496
|
+
skipBytes(reader, 1); // padding
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// 1077 resource has more precise data and is used if present
|
|
500
|
+
if (!target.alphaChannelDisplayInfo) target.alphaChannelDisplayInfo = info;
|
|
501
|
+
},
|
|
502
|
+
() => { },
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
addHandler(
|
|
506
|
+
1077, // Display info (alpha and spot channels)
|
|
507
|
+
target => target.alphaChannelDisplayInfo !== undefined,
|
|
356
508
|
(reader, target, left) => {
|
|
357
|
-
|
|
358
|
-
(
|
|
509
|
+
const version = readUint32(reader);
|
|
510
|
+
if (version !== 1) throw new Error(`Invalid display info version: ${version}`);
|
|
511
|
+
|
|
512
|
+
target.alphaChannelDisplayInfo = [];
|
|
513
|
+
|
|
514
|
+
while (left() >= 13) {
|
|
515
|
+
target.alphaChannelDisplayInfo.push(readDisplayInfo(reader));
|
|
516
|
+
}
|
|
359
517
|
},
|
|
360
518
|
(writer, target) => {
|
|
361
|
-
|
|
519
|
+
writeUint32(writer, 1); // version
|
|
520
|
+
|
|
521
|
+
for (const info of target.alphaChannelDisplayInfo!) {
|
|
522
|
+
if (!info.color && info.rawColor) {
|
|
523
|
+
writeUint16(writer, info.rawColor.colorSpace);
|
|
524
|
+
for (let i = 0; i < 4; i++) writeUint16(writer, info.rawColor.values[i] | 0);
|
|
525
|
+
} else {
|
|
526
|
+
writeColor(writer, info.color || { r: 255, g: 0, b: 0 });
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
writeUint16(writer, Math.round(clamp(info.opacity, 0, 1) * 100));
|
|
530
|
+
writeUint8(writer, Math.max(0, displayInfoKinds.indexOf(info.kind)));
|
|
531
|
+
}
|
|
362
532
|
},
|
|
363
533
|
);
|
|
364
534
|
|
|
@@ -452,42 +622,132 @@ addHandler(
|
|
|
452
622
|
},
|
|
453
623
|
);
|
|
454
624
|
|
|
455
|
-
|
|
456
|
-
10000, // Print flags
|
|
457
|
-
target =>
|
|
458
|
-
(reader, target
|
|
459
|
-
|
|
460
|
-
(
|
|
625
|
+
addHandler(
|
|
626
|
+
10000, // Print flags information
|
|
627
|
+
target => target.printFlagsInfo !== undefined,
|
|
628
|
+
(reader, target) => {
|
|
629
|
+
const version = readUint16(reader);
|
|
630
|
+
if (version !== 1) throw new Error(`Invalid print flags information version: ${version}`);
|
|
631
|
+
const centerCropMarks = !!readUint8(reader);
|
|
632
|
+
skipBytes(reader, 1);
|
|
633
|
+
const bleedWidth = readUint32(reader);
|
|
634
|
+
const bleedWidthScale = readUint16(reader);
|
|
635
|
+
target.printFlagsInfo = { centerCropMarks, bleedWidth, bleedWidthScale };
|
|
461
636
|
},
|
|
462
637
|
(writer, target) => {
|
|
463
|
-
|
|
638
|
+
const info = target.printFlagsInfo!;
|
|
639
|
+
writeUint16(writer, 1); // version
|
|
640
|
+
writeUint8(writer, info.centerCropMarks ? 1 : 0);
|
|
641
|
+
writeUint8(writer, 0);
|
|
642
|
+
writeUint32(writer, info.bleedWidth | 0);
|
|
643
|
+
writeUint16(writer, info.bleedWidthScale | 0);
|
|
464
644
|
},
|
|
465
645
|
);
|
|
466
646
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
target =>
|
|
470
|
-
(reader, target
|
|
471
|
-
|
|
472
|
-
(target as any)._ir1013 = readBytes(reader, left());
|
|
647
|
+
addHandler(
|
|
648
|
+
1046, // Indexed color table count
|
|
649
|
+
target => target.indexedColorCount !== undefined,
|
|
650
|
+
(reader, target) => {
|
|
651
|
+
target.indexedColorCount = readUint16(reader);
|
|
473
652
|
},
|
|
474
653
|
(writer, target) => {
|
|
475
|
-
|
|
654
|
+
writeUint16(writer, target.indexedColorCount!);
|
|
476
655
|
},
|
|
477
656
|
);
|
|
478
657
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
target =>
|
|
482
|
-
(reader, target
|
|
483
|
-
|
|
484
|
-
(target as any)._ir1016 = readBytes(reader, left());
|
|
658
|
+
addHandler(
|
|
659
|
+
1047, // Transparency index
|
|
660
|
+
target => target.transparencyIndex !== undefined,
|
|
661
|
+
(reader, target) => {
|
|
662
|
+
target.transparencyIndex = readUint16(reader);
|
|
485
663
|
},
|
|
486
664
|
(writer, target) => {
|
|
487
|
-
|
|
665
|
+
writeUint16(writer, target.transparencyIndex!);
|
|
488
666
|
},
|
|
489
667
|
);
|
|
490
668
|
|
|
669
|
+
const halftoneFrequencyUnits: HalftoneScreen['frequencyUnits'][] = ['lines/inch', 'lines/cm']; // 1, 2
|
|
670
|
+
const halftoneShapes: (HalftoneScreen['shape'] | undefined)[] = ['round', 'ellipse', 'line', 'square', 'cross', undefined, 'diamond']; // 0 - 6
|
|
671
|
+
|
|
672
|
+
function readHalftoneScreens(reader: PsdReader, left: () => number) {
|
|
673
|
+
const screens: HalftoneScreen[] = [];
|
|
674
|
+
|
|
675
|
+
while (left() >= 18) {
|
|
676
|
+
const frequency = readFixedPoint32(reader);
|
|
677
|
+
const frequencyUnits = halftoneFrequencyUnits[readUint16(reader) - 1];
|
|
678
|
+
if (!frequencyUnits) throw new Error('Invalid halftone screen frequency units');
|
|
679
|
+
const angle = readFixedPoint32(reader);
|
|
680
|
+
const shape = halftoneShapes[readInt16(reader)];
|
|
681
|
+
if (!shape) throw new Error('Invalid halftone screen shape');
|
|
682
|
+
skipBytes(reader, 4);
|
|
683
|
+
const accurateScreens = !!readUint8(reader);
|
|
684
|
+
const printerDefaultScreens = !!readUint8(reader);
|
|
685
|
+
screens.push({ frequency, frequencyUnits, angle, shape, accurateScreens, printerDefaultScreens });
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
return screens;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function writeHalftoneScreens(writer: PsdWriter, screens: HalftoneScreen[]) {
|
|
692
|
+
for (const screen of screens) {
|
|
693
|
+
writeFixedPoint32(writer, screen.frequency);
|
|
694
|
+
writeUint16(writer, Math.max(0, halftoneFrequencyUnits.indexOf(screen.frequencyUnits)) + 1);
|
|
695
|
+
writeFixedPoint32(writer, screen.angle);
|
|
696
|
+
writeInt16(writer, Math.max(0, halftoneShapes.indexOf(screen.shape)));
|
|
697
|
+
writeZeros(writer, 4);
|
|
698
|
+
writeUint8(writer, screen.accurateScreens ? 1 : 0);
|
|
699
|
+
writeUint8(writer, screen.printerDefaultScreens ? 1 : 0);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
addHandler(
|
|
704
|
+
1012, // Grayscale and multichannel halftoning information
|
|
705
|
+
target => target.grayscaleHalftoneScreens !== undefined,
|
|
706
|
+
(reader, target, left) => target.grayscaleHalftoneScreens = readHalftoneScreens(reader, left),
|
|
707
|
+
(writer, target) => writeHalftoneScreens(writer, target.grayscaleHalftoneScreens!),
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
addHandler(
|
|
711
|
+
1013, // Color halftoning information
|
|
712
|
+
target => target.colorHalftoneScreens !== undefined,
|
|
713
|
+
(reader, target, left) => target.colorHalftoneScreens = readHalftoneScreens(reader, left),
|
|
714
|
+
(writer, target) => writeHalftoneScreens(writer, target.colorHalftoneScreens!),
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
function readTransferFunctions(reader: PsdReader, left: () => number) {
|
|
718
|
+
const functions: PrintTransferFunction[] = [];
|
|
719
|
+
|
|
720
|
+
while (left() >= 28) {
|
|
721
|
+
const curve: number[] = [];
|
|
722
|
+
for (let i = 0; i < 13; i++) curve.push(readInt16(reader));
|
|
723
|
+
const override = !!readUint16(reader);
|
|
724
|
+
functions.push({ curve, override });
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return functions;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function writeTransferFunctions(writer: PsdWriter, functions: PrintTransferFunction[]) {
|
|
731
|
+
for (const f of functions) {
|
|
732
|
+
for (let i = 0; i < 13; i++) writeInt16(writer, f.curve[i] ?? -1);
|
|
733
|
+
writeUint16(writer, f.override ? 1 : 0);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
addHandler(
|
|
738
|
+
1015, // Grayscale and multichannel transfer function
|
|
739
|
+
target => target.grayscaleTransferFunctions !== undefined,
|
|
740
|
+
(reader, target, left) => target.grayscaleTransferFunctions = readTransferFunctions(reader, left),
|
|
741
|
+
(writer, target) => writeTransferFunctions(writer, target.grayscaleTransferFunctions!),
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
addHandler(
|
|
745
|
+
1016, // Color transfer functions
|
|
746
|
+
target => target.colorTransferFunctions !== undefined,
|
|
747
|
+
(reader, target, left) => target.colorTransferFunctions = readTransferFunctions(reader, left),
|
|
748
|
+
(writer, target) => writeTransferFunctions(writer, target.colorTransferFunctions!),
|
|
749
|
+
);
|
|
750
|
+
|
|
491
751
|
interface CountInformationDesc {
|
|
492
752
|
Vrsn: 1;
|
|
493
753
|
countGroupList: {
|
|
@@ -609,17 +869,20 @@ addHandler(
|
|
|
609
869
|
|
|
610
870
|
if (version !== 1) throw new Error(`Invalid 1032 resource version: ${version}`);
|
|
611
871
|
|
|
612
|
-
target.gridAndGuidesInformation
|
|
613
|
-
|
|
614
|
-
guides: [],
|
|
615
|
-
};
|
|
872
|
+
const previous = target.gridAndGuidesInformation?.guides; // in case guides were already read from 1092
|
|
873
|
+
const guides: Guide[] = [];
|
|
616
874
|
|
|
617
875
|
for (let i = 0; i < count; i++) {
|
|
618
|
-
|
|
619
|
-
location:
|
|
876
|
+
const guide: Guide = {
|
|
877
|
+
location: readInt32(reader) / 32,
|
|
620
878
|
direction: readUint8(reader) ? 'horizontal' : 'vertical'
|
|
621
|
-
}
|
|
879
|
+
};
|
|
880
|
+
if (previous?.length === count && previous[i].color) guide.color = previous[i].color;
|
|
881
|
+
if (previous?.length === count && previous[i].id) guide.id = previous[i].id;
|
|
882
|
+
guides.push(guide);
|
|
622
883
|
}
|
|
884
|
+
|
|
885
|
+
target.gridAndGuidesInformation = { grid: { horizontal, vertical }, guides };
|
|
623
886
|
},
|
|
624
887
|
(writer, target) => {
|
|
625
888
|
const info = target.gridAndGuidesInformation!;
|
|
@@ -627,17 +890,102 @@ addHandler(
|
|
|
627
890
|
const guides = info.guides || [];
|
|
628
891
|
|
|
629
892
|
writeUint32(writer, 1);
|
|
630
|
-
writeUint32(writer, grid.horizontal);
|
|
631
|
-
writeUint32(writer, grid.vertical);
|
|
893
|
+
writeUint32(writer, Math.round(grid.horizontal));
|
|
894
|
+
writeUint32(writer, Math.round(grid.vertical));
|
|
632
895
|
writeUint32(writer, guides.length);
|
|
633
896
|
|
|
634
897
|
for (const g of guides) {
|
|
635
|
-
|
|
898
|
+
writeInt32(writer, Math.round(g.location * 32));
|
|
636
899
|
writeUint8(writer, g.direction === 'horizontal' ? 1 : 0);
|
|
637
900
|
}
|
|
638
901
|
},
|
|
639
902
|
);
|
|
640
903
|
|
|
904
|
+
type Guide = NonNullable<NonNullable<ImageResources['gridAndGuidesInformation']>['guides']>[number];
|
|
905
|
+
|
|
906
|
+
const defaultGuideColor = { r: 74, g: 255, b: 255 }; // Photoshop default (cyan)
|
|
907
|
+
|
|
908
|
+
addHandler(
|
|
909
|
+
1092, // Grid and guides information with guide colors (same as 1032 with color of each guide)
|
|
910
|
+
target => target.gridAndGuidesInformation !== undefined,
|
|
911
|
+
(reader, target) => {
|
|
912
|
+
const version = readUint32(reader);
|
|
913
|
+
if (version !== 2) throw new Error(`Invalid 1092 resource version: ${version}`);
|
|
914
|
+
const horizontal = readUint32(reader);
|
|
915
|
+
const vertical = readUint32(reader);
|
|
916
|
+
const count = readUint32(reader);
|
|
917
|
+
const guides: Guide[] = [];
|
|
918
|
+
|
|
919
|
+
for (let i = 0; i < count; i++) {
|
|
920
|
+
const location = readInt32(reader) / 32;
|
|
921
|
+
const direction = readUint8(reader) ? 'horizontal' : 'vertical';
|
|
922
|
+
skipBytes(reader, 1);
|
|
923
|
+
const color = { r: readUint8(reader), g: readUint8(reader), b: readUint8(reader) };
|
|
924
|
+
guides.push({ location, direction, color });
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
const existing = target.gridAndGuidesInformation?.guides;
|
|
928
|
+
|
|
929
|
+
if (existing && existing.length === count) {
|
|
930
|
+
existing.forEach((guide, i) => guide.color = guides[i].color);
|
|
931
|
+
} else {
|
|
932
|
+
target.gridAndGuidesInformation = { grid: { horizontal, vertical }, guides };
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
(writer, target) => {
|
|
936
|
+
const info = target.gridAndGuidesInformation!;
|
|
937
|
+
const grid = info.grid || { horizontal: 18 * 32, vertical: 18 * 32 };
|
|
938
|
+
const guides = info.guides || [];
|
|
939
|
+
|
|
940
|
+
writeUint32(writer, 2); // version
|
|
941
|
+
writeUint32(writer, Math.round(grid.horizontal));
|
|
942
|
+
writeUint32(writer, Math.round(grid.vertical));
|
|
943
|
+
writeUint32(writer, guides.length);
|
|
944
|
+
|
|
945
|
+
for (const g of guides) {
|
|
946
|
+
const color = g.color || defaultGuideColor;
|
|
947
|
+
writeInt32(writer, Math.round(g.location * 32));
|
|
948
|
+
writeUint8(writer, g.direction === 'horizontal' ? 1 : 0);
|
|
949
|
+
writeUint8(writer, 0);
|
|
950
|
+
writeUint8(writer, Math.round(color.r));
|
|
951
|
+
writeUint8(writer, Math.round(color.g));
|
|
952
|
+
writeUint8(writer, Math.round(color.b));
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
const emptyGuid = '00000000-0000-0000-0000-000000000000';
|
|
958
|
+
|
|
959
|
+
addHandler(
|
|
960
|
+
1097, // Guide ids
|
|
961
|
+
target => !!target.gridAndGuidesInformation && (target.gridAndGuidesInformation.guides || []).every(g => g.id),
|
|
962
|
+
(reader, target) => {
|
|
963
|
+
const count = readUint32(reader);
|
|
964
|
+
const ids: string[] = [];
|
|
965
|
+
|
|
966
|
+
for (let i = 0; i < count; i++) {
|
|
967
|
+
ids.push(readAsciiString(reader, readUint32(reader)));
|
|
968
|
+
readUint32(reader); // unknown, always 0
|
|
969
|
+
readAsciiString(reader, readUint32(reader)); // unknown, always empty guid
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
const guides = target.gridAndGuidesInformation?.guides;
|
|
973
|
+
if (guides && guides.length === count) guides.forEach((guide, i) => guide.id = ids[i]);
|
|
974
|
+
},
|
|
975
|
+
(writer, target) => {
|
|
976
|
+
const guides = target.gridAndGuidesInformation!.guides || [];
|
|
977
|
+
writeUint32(writer, guides.length);
|
|
978
|
+
|
|
979
|
+
for (const g of guides) {
|
|
980
|
+
writeUint32(writer, g.id!.length);
|
|
981
|
+
writeAsciiString(writer, g.id!);
|
|
982
|
+
writeUint32(writer, 0);
|
|
983
|
+
writeUint32(writer, emptyGuid.length);
|
|
984
|
+
writeAsciiString(writer, emptyGuid);
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
);
|
|
988
|
+
|
|
641
989
|
interface LayerCompsDescriptor {
|
|
642
990
|
list: {
|
|
643
991
|
_classID: 'Comp';
|
|
@@ -665,10 +1013,10 @@ addHandler(
|
|
|
665
1013
|
capturedInfo: item.capturedInfo,
|
|
666
1014
|
});
|
|
667
1015
|
|
|
668
|
-
if (
|
|
1016
|
+
if (item.comment !== undefined) target.layerComps.list[target.layerComps.list.length - 1].comment = item.comment;
|
|
669
1017
|
}
|
|
670
1018
|
|
|
671
|
-
if (
|
|
1019
|
+
if (desc.lastAppliedComp !== undefined) target.layerComps.lastApplied = desc.lastAppliedComp;
|
|
672
1020
|
},
|
|
673
1021
|
(writer, target) => {
|
|
674
1022
|
const layerComps = target.layerComps!;
|
|
@@ -678,13 +1026,13 @@ addHandler(
|
|
|
678
1026
|
const t: LayerCompsDescriptor['list'][0] = {} as any;
|
|
679
1027
|
t._classID = 'Comp';
|
|
680
1028
|
t['Nm '] = item.name;
|
|
681
|
-
if (
|
|
1029
|
+
if (item.comment !== undefined) t.comment = item.comment;
|
|
682
1030
|
t.compID = item.id;
|
|
683
1031
|
t.capturedInfo = item.capturedInfo;
|
|
684
1032
|
desc.list.push(t);
|
|
685
1033
|
}
|
|
686
1034
|
|
|
687
|
-
if (
|
|
1035
|
+
if (layerComps.lastApplied !== undefined) desc.lastAppliedComp = layerComps.lastApplied;
|
|
688
1036
|
|
|
689
1037
|
// console.log('CompList', require('util').inspect(desc, false, 99, true));
|
|
690
1038
|
writeVersionAndDescriptor(writer, '', 'CompList', desc);
|
|
@@ -747,8 +1095,8 @@ addHandler(
|
|
|
747
1095
|
numBefore: onionSkins.framesBefore,
|
|
748
1096
|
numAfter: onionSkins.framesAfter,
|
|
749
1097
|
Spcn: onionSkins.frameSpacing,
|
|
750
|
-
minOpacity: (onionSkins.minOpacity * 100)
|
|
751
|
-
maxOpacity: (onionSkins.maxOpacity * 100)
|
|
1098
|
+
minOpacity: Math.round(onionSkins.minOpacity * 100),
|
|
1099
|
+
maxOpacity: Math.round(onionSkins.maxOpacity * 100),
|
|
752
1100
|
BlnM: Math.max(0, onionSkinsBlendModes.indexOf(onionSkins.blendMode)),
|
|
753
1101
|
};
|
|
754
1102
|
|
|
@@ -855,7 +1203,7 @@ addHandler(
|
|
|
855
1203
|
LCnt: timeline.repeats,
|
|
856
1204
|
globalTrackList: serializeTrackList(timeline.globalTracks),
|
|
857
1205
|
audioClipGroupList: {
|
|
858
|
-
audioClipGroupList: timeline.audioClipGroups
|
|
1206
|
+
audioClipGroupList: (timeline.audioClipGroups ?? []).map(a => ({
|
|
859
1207
|
groupID: a.id,
|
|
860
1208
|
muted: a.muted,
|
|
861
1209
|
audioClipList: a.audioClips.map<TimelineAudioClipDescriptor>(c => ({
|
|
@@ -1072,8 +1420,13 @@ addHandler(
|
|
|
1072
1420
|
}
|
|
1073
1421
|
if (leftBytes()) {
|
|
1074
1422
|
const desc = readVersionAndDescriptor(reader) as SlicesDesc;
|
|
1423
|
+
const slicesById = new Map<number, typeof slices[0]>();
|
|
1424
|
+
for (const s of slices) {
|
|
1425
|
+
if (!slicesById.has(s.id)) slicesById.set(s.id, s);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1075
1428
|
desc.slices.forEach(d => {
|
|
1076
|
-
const slice =
|
|
1429
|
+
const slice = slicesById.get(d.sliceID);
|
|
1077
1430
|
if (slice) {
|
|
1078
1431
|
slice.topOutset = d.topOutset;
|
|
1079
1432
|
slice.leftOutset = d.leftOutset;
|
|
@@ -1227,16 +1580,14 @@ addHandler(
|
|
|
1227
1580
|
},
|
|
1228
1581
|
);
|
|
1229
1582
|
|
|
1230
|
-
|
|
1583
|
+
addHandler(
|
|
1231
1584
|
1039, // ICC Profile
|
|
1232
|
-
target =>
|
|
1585
|
+
target => target.iccProfile !== undefined,
|
|
1233
1586
|
(reader, target, left) => {
|
|
1234
|
-
|
|
1235
|
-
LOG_MOCK_HANDLERS && console.log('image resource 1039', left());
|
|
1236
|
-
(target as any)._ir1039 = readBytes(reader, left());
|
|
1587
|
+
target.iccProfile = readBytes(reader, left());
|
|
1237
1588
|
},
|
|
1238
1589
|
(writer, target) => {
|
|
1239
|
-
writeBytes(writer,
|
|
1590
|
+
writeBytes(writer, target.iccProfile!);
|
|
1240
1591
|
},
|
|
1241
1592
|
);
|
|
1242
1593
|
|
|
@@ -1247,6 +1598,47 @@ addHandler(
|
|
|
1247
1598
|
(writer, target) => writeUint32(writer, target.idsSeedNumber!),
|
|
1248
1599
|
);
|
|
1249
1600
|
|
|
1601
|
+
addHandler(
|
|
1602
|
+
1038, // Color samplers (Photoshop 5.0, replaced by 1073 in CS3)
|
|
1603
|
+
target => target.colorSamplers !== undefined,
|
|
1604
|
+
(reader, target, left) => {
|
|
1605
|
+
const version = readUint32(reader);
|
|
1606
|
+
if (version !== 1) throw new Error(`Invalid color samplers version: ${version}`);
|
|
1607
|
+
const count = readUint32(reader);
|
|
1608
|
+
target.colorSamplers = [];
|
|
1609
|
+
|
|
1610
|
+
for (let i = 0; i < count && left() >= 10; i++) {
|
|
1611
|
+
// vertical and horizontal position in 1/16 pixel (inferred from sample files, the specification describes
|
|
1612
|
+
// these values as horizontal and vertical fixed point numbers)
|
|
1613
|
+
const y = readInt32(reader) / 16;
|
|
1614
|
+
const x = readInt32(reader) / 16;
|
|
1615
|
+
const colorSpace = readInt16(reader);
|
|
1616
|
+
target.colorSamplers.push({ x, y, colorSpace });
|
|
1617
|
+
}
|
|
1618
|
+
},
|
|
1619
|
+
(writer, target) => {
|
|
1620
|
+
writeUint32(writer, 1); // version
|
|
1621
|
+
writeUint32(writer, target.colorSamplers!.length);
|
|
1622
|
+
|
|
1623
|
+
for (const sampler of target.colorSamplers!) {
|
|
1624
|
+
writeInt32(writer, Math.round(sampler.y * 16));
|
|
1625
|
+
writeInt32(writer, Math.round(sampler.x * 16));
|
|
1626
|
+
writeInt16(writer, sampler.colorSpace);
|
|
1627
|
+
}
|
|
1628
|
+
},
|
|
1629
|
+
);
|
|
1630
|
+
|
|
1631
|
+
addHandler(
|
|
1632
|
+
1042, // Effects visible (only present when effects are hidden)
|
|
1633
|
+
target => target.effectsVisible !== undefined,
|
|
1634
|
+
(reader, target) => {
|
|
1635
|
+
target.effectsVisible = !!readUint8(reader);
|
|
1636
|
+
},
|
|
1637
|
+
(writer, target) => {
|
|
1638
|
+
writeUint8(writer, target.effectsVisible ? 1 : 0);
|
|
1639
|
+
},
|
|
1640
|
+
);
|
|
1641
|
+
|
|
1250
1642
|
addHandler(
|
|
1251
1643
|
1036,
|
|
1252
1644
|
target => target.thumbnail !== undefined || target.thumbnailRaw !== undefined,
|
|
@@ -1254,14 +1646,39 @@ addHandler(
|
|
|
1254
1646
|
const format = readUint32(reader); // 1 = kJpegRGB, 0 = kRawRGB
|
|
1255
1647
|
const width = readUint32(reader);
|
|
1256
1648
|
const height = readUint32(reader);
|
|
1257
|
-
readUint32(reader); // widthBytes = (width * bits_per_pixel + 31) / 32 * 4.
|
|
1649
|
+
const widthBytes = readUint32(reader); // widthBytes = (width * bits_per_pixel + 31) / 32 * 4.
|
|
1258
1650
|
readUint32(reader); // totalSize = widthBytes * height * planes
|
|
1259
1651
|
readUint32(reader); // sizeAfterCompression
|
|
1260
1652
|
const bitsPerPixel = readUint16(reader); // 24
|
|
1261
|
-
|
|
1653
|
+
readUint16(reader); // planes, should be 1 (some applications write 3)
|
|
1654
|
+
|
|
1655
|
+
if (format === 0 && bitsPerPixel === 24 && widthBytes >= width * 3 && widthBytes * height <= left()) {
|
|
1656
|
+
// raw RGB data, rows are padded to 4 bytes
|
|
1657
|
+
if (reader.useRawThumbnail) {
|
|
1658
|
+
reader.logMissingFeatures && reader.log('Raw thumbnail data is not supported with useRawThumbnail option');
|
|
1659
|
+
skipBytes(reader, left());
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1262
1662
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1663
|
+
const data = readBytes(reader, widthBytes * height);
|
|
1664
|
+
const imageData = createImageData(width, height);
|
|
1665
|
+
|
|
1666
|
+
for (let y = 0, dst = 0; y < height; y++) {
|
|
1667
|
+
for (let x = 0, src = y * widthBytes; x < width; x++, src += 3, dst += 4) {
|
|
1668
|
+
imageData.data[dst + 0] = data[src + 0];
|
|
1669
|
+
imageData.data[dst + 1] = data[src + 1];
|
|
1670
|
+
imageData.data[dst + 2] = data[src + 2];
|
|
1671
|
+
imageData.data[dst + 3] = 255;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
target.thumbnail = imageDataToCanvas(imageData);
|
|
1676
|
+
skipBytes(reader, left());
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
if (format !== 1 || bitsPerPixel !== 24) {
|
|
1681
|
+
reader.logMissingFeatures && reader.log(`Invalid thumbnail data (format: ${format}, bitsPerPixel: ${bitsPerPixel})`);
|
|
1265
1682
|
skipBytes(reader, left());
|
|
1266
1683
|
return;
|
|
1267
1684
|
}
|
|
@@ -1272,7 +1689,7 @@ addHandler(
|
|
|
1272
1689
|
if (reader.useRawThumbnail) {
|
|
1273
1690
|
target.thumbnailRaw = { width, height, data };
|
|
1274
1691
|
} else if (data.byteLength) {
|
|
1275
|
-
target.thumbnail = createCanvasFromData(data);
|
|
1692
|
+
target.thumbnail = createCanvasFromData(data, reader);
|
|
1276
1693
|
}
|
|
1277
1694
|
},
|
|
1278
1695
|
(writer, target) => {
|
|
@@ -1340,15 +1757,14 @@ addHandler(
|
|
|
1340
1757
|
},
|
|
1341
1758
|
);
|
|
1342
1759
|
|
|
1343
|
-
|
|
1344
|
-
1058, // EXIF data 1
|
|
1345
|
-
target =>
|
|
1760
|
+
addHandler(
|
|
1761
|
+
1058, // EXIF data 1
|
|
1762
|
+
target => target.exifData !== undefined,
|
|
1346
1763
|
(reader, target, left) => {
|
|
1347
|
-
|
|
1348
|
-
(target as any)._ir1058 = readBytes(reader, left());
|
|
1764
|
+
target.exifData = readBytes(reader, left());
|
|
1349
1765
|
},
|
|
1350
1766
|
(writer, target) => {
|
|
1351
|
-
writeBytes(writer,
|
|
1767
|
+
writeBytes(writer, target.exifData!);
|
|
1352
1768
|
},
|
|
1353
1769
|
);
|
|
1354
1770
|
|
|
@@ -1374,32 +1790,116 @@ addHandler(
|
|
|
1374
1790
|
},
|
|
1375
1791
|
);
|
|
1376
1792
|
|
|
1377
|
-
interface
|
|
1793
|
+
interface Descriptor1088Read {
|
|
1378
1794
|
'null': string[];
|
|
1379
1795
|
}
|
|
1380
1796
|
|
|
1797
|
+
interface Descriptor1088Write {
|
|
1798
|
+
'null': DescriptorReferenceItem[];
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1381
1801
|
addHandler(
|
|
1382
1802
|
1088,
|
|
1383
1803
|
target => target.pathSelectionState !== undefined,
|
|
1384
1804
|
(reader, target, _left) => {
|
|
1385
|
-
const desc:
|
|
1805
|
+
const desc: Descriptor1088Read = readVersionAndDescriptor(reader);
|
|
1386
1806
|
target.pathSelectionState = desc['null'];
|
|
1387
1807
|
},
|
|
1388
1808
|
(writer, target) => {
|
|
1389
|
-
const desc:
|
|
1809
|
+
const desc: Descriptor1088Write = { 'null': pathSelectionStateToReference(target.pathSelectionState!) };
|
|
1390
1810
|
writeVersionAndDescriptor(writer, '', 'null', desc);
|
|
1391
1811
|
},
|
|
1392
1812
|
);
|
|
1393
1813
|
|
|
1394
|
-
|
|
1395
|
-
1025,
|
|
1396
|
-
target =>
|
|
1814
|
+
addHandler(
|
|
1815
|
+
1025, // Work path
|
|
1816
|
+
target => target.workPath !== undefined,
|
|
1817
|
+
(reader, target, left, { width, height }) => {
|
|
1818
|
+
target.workPath = { paths: [] };
|
|
1819
|
+
readVectorMask(reader, target.workPath, width, height, left());
|
|
1820
|
+
skipBytes(reader, left());
|
|
1821
|
+
},
|
|
1822
|
+
(writer, target, _index, { width, height }) => {
|
|
1823
|
+
writeVectorMask(writer, target.workPath!, width, height);
|
|
1824
|
+
},
|
|
1825
|
+
);
|
|
1826
|
+
|
|
1827
|
+
const MAX_SAVED_PATHS = 999; // ids 2000-2998
|
|
1828
|
+
|
|
1829
|
+
addHandler(
|
|
1830
|
+
2000, // Saved paths (one resource for each path, named after the path)
|
|
1831
|
+
target => target.savedPaths ? Math.min(target.savedPaths.length, MAX_SAVED_PATHS) : 0,
|
|
1832
|
+
(reader, target, left, { signature, id, name, width, height }) => {
|
|
1833
|
+
if (signature !== '8BIM') { // ImageReady ('MeSa') resources use the same ids for other data
|
|
1834
|
+
reader.logMissingFeatures && reader.log(`Unhandled image resource: ${signature} ${id}`);
|
|
1835
|
+
skipBytes(reader, left());
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
const savedPaths = target.savedPaths ??= [];
|
|
1840
|
+
const path: SavedPath = { name: decodeEncodedString(reader, name), paths: [] };
|
|
1841
|
+
readVectorMask(reader, path, width, height, left());
|
|
1842
|
+
skipBytes(reader, left());
|
|
1843
|
+
|
|
1844
|
+
const keyDescriptorList = target.savedPathsOrigination?.[savedPaths.length];
|
|
1845
|
+
if (keyDescriptorList) path.vectorOrigination = { keyDescriptorList };
|
|
1846
|
+
|
|
1847
|
+
savedPaths.push(path);
|
|
1848
|
+
},
|
|
1849
|
+
(writer, target, index, { width, height }) => {
|
|
1850
|
+
writeVectorMask(writer, target.savedPaths![index], width, height);
|
|
1851
|
+
},
|
|
1852
|
+
{ keyCount: MAX_SAVED_PATHS, name: (target, index) => toShortAsciiString(target.savedPaths![index].name) },
|
|
1853
|
+
);
|
|
1854
|
+
|
|
1855
|
+
interface OriginPathInfoDescriptor {
|
|
1856
|
+
keyRootDescriptorList: KeyDescriptorListDescriptor[];
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
addHandler(
|
|
1860
|
+
3000, // Origin path info (origination data of saved paths)
|
|
1861
|
+
target => !!target.savedPaths?.some(path => path.vectorOrigination),
|
|
1397
1862
|
(reader, target, left) => {
|
|
1398
|
-
|
|
1399
|
-
|
|
1863
|
+
const desc = readVersionAndDescriptor(reader) as OriginPathInfoDescriptor;
|
|
1864
|
+
|
|
1865
|
+
desc.keyRootDescriptorList.forEach((item, i) => {
|
|
1866
|
+
const keyDescriptorList = parseKeyDescriptorList(item);
|
|
1867
|
+
if (!keyDescriptorList.length) return; // written for paths without origination data
|
|
1868
|
+
|
|
1869
|
+
const path = target.savedPaths?.[i];
|
|
1870
|
+
|
|
1871
|
+
if (path) {
|
|
1872
|
+
path.vectorOrigination = { keyDescriptorList };
|
|
1873
|
+
} else { // saved paths are stored after this resource
|
|
1874
|
+
(target.savedPathsOrigination ??= [])[i] = keyDescriptorList;
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
skipBytes(reader, left());
|
|
1400
1879
|
},
|
|
1401
1880
|
(writer, target) => {
|
|
1402
|
-
|
|
1881
|
+
const desc: OriginPathInfoDescriptor = {
|
|
1882
|
+
keyRootDescriptorList: target.savedPaths!.slice(0, MAX_SAVED_PATHS)
|
|
1883
|
+
.map(path => serializeKeyDescriptorList(path.vectorOrigination?.keyDescriptorList ?? [])),
|
|
1884
|
+
};
|
|
1885
|
+
writeVersionAndDescriptor(writer, '', 'null', desc);
|
|
1886
|
+
},
|
|
1887
|
+
{ name: () => 'OriginDataIRB' },
|
|
1888
|
+
);
|
|
1889
|
+
|
|
1890
|
+
addHandler(
|
|
1891
|
+
2999, // Clipping path
|
|
1892
|
+
target => target.clippingPath !== undefined,
|
|
1893
|
+
(reader, target, left) => {
|
|
1894
|
+
const name = readEncodedString(reader);
|
|
1895
|
+
const flatness = readFixedPoint32(reader);
|
|
1896
|
+
skipBytes(reader, left()); // fill rule (ignored by Photoshop)
|
|
1897
|
+
target.clippingPath = { name, flatness };
|
|
1898
|
+
},
|
|
1899
|
+
(writer, target) => {
|
|
1900
|
+
writeEncodedString(writer, target.clippingPath!.name);
|
|
1901
|
+
writeFixedPoint32(writer, target.clippingPath!.flatness);
|
|
1902
|
+
writeUint16(writer, 1); // fill rule (ignored by Photoshop)
|
|
1403
1903
|
},
|
|
1404
1904
|
);
|
|
1405
1905
|
|
|
@@ -1429,13 +1929,28 @@ interface AnimationsDescriptor {
|
|
|
1429
1929
|
FSts: AnimationDescriptor[];
|
|
1430
1930
|
}
|
|
1431
1931
|
|
|
1932
|
+
// plug-in resources are written with consecutive ids starting at 4000, in the same order as Photoshop writes them
|
|
1933
|
+
function pluginResourceKeys(target: InternalImageResources) {
|
|
1934
|
+
const keys: string[] = [];
|
|
1935
|
+
if (target.outputSettings !== undefined) keys.push('mset');
|
|
1936
|
+
if (target.animations !== undefined) keys.push('mani', 'mfri');
|
|
1937
|
+
return keys;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1432
1940
|
addHandler(
|
|
1433
|
-
4000, // Plug-In resource(s)
|
|
1434
|
-
target => target.
|
|
1941
|
+
4000, // Plug-In resource(s), identified by key stored in the data (ids 4000-4999)
|
|
1942
|
+
target => pluginResourceKeys(target).length,
|
|
1435
1943
|
(reader, target, left) => {
|
|
1436
1944
|
const key = readSignature(reader);
|
|
1437
1945
|
|
|
1438
|
-
if (key === '
|
|
1946
|
+
if (key === 'mset') {
|
|
1947
|
+
// Save for Web output settings
|
|
1948
|
+
target.outputSettings = readVersionAndDescriptor(reader, true);
|
|
1949
|
+
skipBytes(reader, left());
|
|
1950
|
+
} else if (key === 'mfri') {
|
|
1951
|
+
// frame count, active frame and animation count, same data as in animations (mani)
|
|
1952
|
+
skipBytes(reader, left());
|
|
1953
|
+
} else if (key === 'mani') {
|
|
1439
1954
|
checkSignature(reader, 'IRFR');
|
|
1440
1955
|
readSection(reader, 1, left => {
|
|
1441
1956
|
while (left() > 0) {
|
|
@@ -1463,24 +1978,43 @@ addHandler(
|
|
|
1463
1978
|
|
|
1464
1979
|
// console.log('#4000 AnDs', require('util').inspect(desc, false, 99, true));
|
|
1465
1980
|
// console.log('#4000 AnDs:result', require('util').inspect(target.animations, false, 99, true));
|
|
1981
|
+
skipBytes(reader, left()); // padding
|
|
1466
1982
|
} else if (key === 'Roll') {
|
|
1467
1983
|
const bytes = readBytes(reader, left());
|
|
1468
1984
|
reader.logDevFeatures && reader.log('#4000 Roll', bytes);
|
|
1469
1985
|
} else {
|
|
1470
1986
|
reader.logMissingFeatures && reader.log('Unhandled subsection in #4000', key);
|
|
1987
|
+
skipBytes(reader, left());
|
|
1471
1988
|
}
|
|
1472
1989
|
});
|
|
1473
1990
|
}
|
|
1474
1991
|
});
|
|
1992
|
+
|
|
1993
|
+
skipBytes(reader, left()); // unknown data after animations section
|
|
1475
1994
|
} else if (key === 'mopt') {
|
|
1476
1995
|
const bytes = readBytes(reader, left());
|
|
1477
1996
|
reader.logDevFeatures && reader.log('#4000 mopt', bytes);
|
|
1478
1997
|
} else {
|
|
1479
|
-
reader.logMissingFeatures && reader.log(
|
|
1998
|
+
reader.logMissingFeatures && reader.log(`Unhandled plug-in resource key: ${key}`);
|
|
1999
|
+
skipBytes(reader, left());
|
|
1480
2000
|
}
|
|
1481
2001
|
},
|
|
1482
|
-
(writer, target) => {
|
|
1483
|
-
|
|
2002
|
+
(writer, target, index) => {
|
|
2003
|
+
const key = pluginResourceKeys(target)[index];
|
|
2004
|
+
|
|
2005
|
+
if (key === 'mset') {
|
|
2006
|
+
writeSignature(writer, 'mset');
|
|
2007
|
+
writeVersionAndDescriptor(writer, '', 'null', target.outputSettings, outputSettingsRoot);
|
|
2008
|
+
} else if (key === 'mfri') {
|
|
2009
|
+
const animations = target.animations!;
|
|
2010
|
+
writeSignature(writer, 'mfri');
|
|
2011
|
+
writeUint32(writer, 2); // version
|
|
2012
|
+
writeUint32(writer, 16); // length
|
|
2013
|
+
writeUint32(writer, animations.frames.length);
|
|
2014
|
+
writeUint32(writer, animations.animations[0]?.activeFrame ?? 0);
|
|
2015
|
+
writeUint32(writer, animations.animations.length);
|
|
2016
|
+
writeUint32(writer, 0);
|
|
2017
|
+
} else if (key === 'mani') {
|
|
1484
2018
|
writeSignature(writer, 'mani');
|
|
1485
2019
|
writeSignature(writer, 'IRFR');
|
|
1486
2020
|
writeSection(writer, 1, () => {
|
|
@@ -1498,7 +2032,7 @@ addHandler(
|
|
|
1498
2032
|
const frame: AnimationFrameDescriptor = {
|
|
1499
2033
|
FrID: f.id,
|
|
1500
2034
|
} as any;
|
|
1501
|
-
if (f.delay) frame.FrDl = (f.delay * 100)
|
|
2035
|
+
if (f.delay) frame.FrDl = Math.round(f.delay * 100);
|
|
1502
2036
|
frame.FrDs = FrmD.encode(f.dispose);
|
|
1503
2037
|
// if (i === 0) frame.FrGA = 30; // ???
|
|
1504
2038
|
desc.FrIn.push(frame);
|
|
@@ -1526,49 +2060,6 @@ addHandler(
|
|
|
1526
2060
|
});
|
|
1527
2061
|
}
|
|
1528
2062
|
},
|
|
2063
|
+
{ keyCount: 1000 },
|
|
1529
2064
|
);
|
|
1530
2065
|
|
|
1531
|
-
// TODO: Unfinished
|
|
1532
|
-
MOCK_HANDLERS && addHandler(
|
|
1533
|
-
4001, // Plug-In resource(s)
|
|
1534
|
-
target => (target as any)._ir4001 !== undefined,
|
|
1535
|
-
(reader, target, left) => {
|
|
1536
|
-
if (MOCK_HANDLERS) {
|
|
1537
|
-
LOG_MOCK_HANDLERS && console.log('image resource 4001', left());
|
|
1538
|
-
(target as any)._ir4001 = readBytes(reader, left());
|
|
1539
|
-
return;
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
const key = readSignature(reader);
|
|
1543
|
-
|
|
1544
|
-
if (key === 'mfri') {
|
|
1545
|
-
const version = readUint32(reader);
|
|
1546
|
-
if (version !== 2) throw new Error('Invalid mfri version');
|
|
1547
|
-
|
|
1548
|
-
const length = readUint32(reader);
|
|
1549
|
-
const bytes = readBytes(reader, length);
|
|
1550
|
-
reader.logDevFeatures && reader.log('mfri', bytes);
|
|
1551
|
-
} else if (key === 'mset') {
|
|
1552
|
-
const desc = readVersionAndDescriptor(reader);
|
|
1553
|
-
reader.logDevFeatures && reader.log('mset', desc);
|
|
1554
|
-
} else {
|
|
1555
|
-
reader.logMissingFeatures && reader.log('Unhandled key in #4001', key);
|
|
1556
|
-
}
|
|
1557
|
-
},
|
|
1558
|
-
(writer, target) => {
|
|
1559
|
-
writeBytes(writer, (target as any)._ir4001);
|
|
1560
|
-
},
|
|
1561
|
-
);
|
|
1562
|
-
|
|
1563
|
-
// TODO: Unfinished
|
|
1564
|
-
MOCK_HANDLERS && addHandler(
|
|
1565
|
-
4002, // Plug-In resource(s)
|
|
1566
|
-
target => (target as any)._ir4002 !== undefined,
|
|
1567
|
-
(reader, target, left) => {
|
|
1568
|
-
LOG_MOCK_HANDLERS && console.log('image resource 4002', left());
|
|
1569
|
-
(target as any)._ir4002 = readBytes(reader, left());
|
|
1570
|
-
},
|
|
1571
|
-
(writer, target) => {
|
|
1572
|
-
writeBytes(writer, (target as any)._ir4002);
|
|
1573
|
-
},
|
|
1574
|
-
);
|