ag-psd 32.0.0 → 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/03e19709 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +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/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/c314aece +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/dc86f000 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +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/f6fd8125 +0 -0
- package/CHANGELOG.md +78 -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 +357 -230
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +54 -2
- package/dist/additionalInfo.js +487 -306
- 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 +1937 -1115
- package/dist/descriptor.d.ts +14 -8
- package/dist/descriptor.js +202 -186
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.js +4 -2
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.d.ts +15 -3
- package/dist/imageResources.js +503 -142
- package/dist/imageResources.js.map +1 -1
- package/dist/jpeg.js +8 -8
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +148 -17
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.d.ts +10 -0
- package/dist/psdReader.js +278 -166
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +1 -0
- package/dist/psdWriter.js +77 -62
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.js +17 -6
- package/dist/text.js.map +1 -1
- package/dist/utf8.js +0 -3
- package/dist/utf8.js.map +1 -1
- package/dist-es/abr.d.ts +11 -4
- package/dist-es/abr.js +357 -230
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +54 -2
- package/dist-es/additionalInfo.js +487 -306
- 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 +14 -8
- package/dist-es/descriptor.js +202 -186
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +1 -1
- package/dist-es/helpers.js +4 -2
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.d.ts +15 -3
- package/dist-es/imageResources.js +503 -142
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/jpeg.js +8 -8
- package/dist-es/jpeg.js.map +1 -1
- package/dist-es/psd.d.ts +148 -17
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.d.ts +10 -0
- package/dist-es/psdReader.js +278 -166
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +1 -0
- package/dist-es/psdWriter.js +77 -62
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.js +17 -6
- package/dist-es/text.js.map +1 -1
- package/dist-es/utf8.js +0 -3
- package/dist-es/utf8.js.map +1 -1
- package/package.json +2 -2
- package/src/abr.ts +375 -235
- package/src/additionalInfo.ts +663 -420
- package/src/ase.ts +66 -61
- package/src/descriptor.ts +199 -195
- package/src/helpers.ts +4 -1
- package/src/imageResources.ts +632 -168
- package/src/jpeg.ts +8 -8
- package/src/psd.ts +156 -30
- package/src/psdReader.ts +273 -172
- package/src/psdWriter.ts +95 -58
- package/src/text.ts +17 -6
- package/src/utf8.ts +0 -4
package/dist/bundle.js
CHANGED
|
@@ -99,261 +99,92 @@ function parseHeightmap(array) {
|
|
|
99
99
|
// return result;
|
|
100
100
|
}
|
|
101
101
|
function readAbr(buffer, options = {}) {
|
|
102
|
-
var _a, _b, _c, _d;
|
|
103
102
|
const reader = (0, psdReader_1.createReader)(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
103
|
+
reader.logMissingFeatures = options.logMissingFeatures;
|
|
104
|
+
reader.throwForMissingFeatures = options.throwForMissingFeatures;
|
|
105
|
+
reader.totalMemoryLimit = 'totalMemoryLimit' in options ? options.totalMemoryLimit : 2 * 1024 * 1024 * 1024;
|
|
106
|
+
// skips invalid or unsupported part of the file
|
|
107
|
+
const skip = (e, what) => {
|
|
108
|
+
if (options.throwForMissingFeatures)
|
|
109
|
+
throw e;
|
|
110
|
+
options.logMissingFeatures && reader.log(`Skipped ${what}: ${e.message}`);
|
|
111
|
+
};
|
|
112
|
+
if (reader.view.byteLength < 4)
|
|
113
|
+
throw new Error('Invalid ABR file');
|
|
104
114
|
const version = (0, psdReader_1.readInt16)(reader);
|
|
105
115
|
const samples = [];
|
|
106
116
|
const brushes = [];
|
|
107
117
|
const patterns = [];
|
|
118
|
+
const brushByPreset = []; // brush for each preset in 'desc' section (brushes that fail to parse are skipped)
|
|
119
|
+
let hierarchy;
|
|
108
120
|
if (version === 1 || version === 2) {
|
|
109
|
-
|
|
121
|
+
readLegacyBrushes(reader, version, samples, brushes, skip);
|
|
110
122
|
}
|
|
111
123
|
else if (version === 6 || version === 7 || version === 9 || version === 10) {
|
|
112
124
|
const minorVersion = (0, psdReader_1.readInt16)(reader);
|
|
113
125
|
if (minorVersion !== 1 && minorVersion !== 2)
|
|
114
126
|
throw new Error('Unsupported ABR minor version');
|
|
115
|
-
|
|
127
|
+
// section header is 12 bytes, ignore any shorter trailing data
|
|
128
|
+
while (reader.offset + 12 <= reader.view.byteLength) {
|
|
116
129
|
(0, psdReader_1.checkSignature)(reader, '8BIM');
|
|
117
130
|
const type = (0, psdReader_1.readSignature)(reader);
|
|
118
131
|
const size = (0, psdReader_1.readUint32)(reader);
|
|
119
|
-
const end = reader.offset + size;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
brushLength
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const y = (0, psdReader_1.readInt32)(reader);
|
|
132
|
-
const x = (0, psdReader_1.readInt32)(reader);
|
|
133
|
-
const h = (0, psdReader_1.readInt32)(reader) - y;
|
|
134
|
-
const w = (0, psdReader_1.readInt32)(reader) - x;
|
|
135
|
-
if (w <= 0 || h <= 0)
|
|
136
|
-
throw new Error('Invalid bounds');
|
|
137
|
-
if (w > MAX_BRUSH_SIZE || h > MAX_BRUSH_SIZE) {
|
|
138
|
-
throw new Error(`Brush sample too large (${w}x${h})`);
|
|
139
|
-
}
|
|
140
|
-
const bithDepth = (0, psdReader_1.readInt16)(reader);
|
|
141
|
-
const compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
|
|
142
|
-
if (compression === 0 && w * h * (bithDepth === 16 ? 2 : 1) > brushEnd - reader.offset) {
|
|
143
|
-
throw new Error('Brush sample data out of bounds');
|
|
144
|
-
}
|
|
145
|
-
const alpha = new Uint8Array(w * h);
|
|
146
|
-
if (bithDepth === 8) {
|
|
147
|
-
if (compression === 0) {
|
|
148
|
-
alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
|
|
149
|
-
}
|
|
150
|
-
else if (compression === 1) {
|
|
151
|
-
(0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
|
|
132
|
+
const end = Math.min(reader.offset + size, reader.view.byteLength);
|
|
133
|
+
try {
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'samp': {
|
|
136
|
+
while (reader.offset + 4 <= end) {
|
|
137
|
+
let brushLength = (0, psdReader_1.readUint32)(reader);
|
|
138
|
+
while (brushLength & 0b11)
|
|
139
|
+
brushLength++; // pad to 4 byte alignment
|
|
140
|
+
const brushEnd = Math.min(reader.offset + brushLength, end);
|
|
141
|
+
try {
|
|
142
|
+
const sample = readSample(reader, brushEnd, minorVersion);
|
|
143
|
+
samples.push(sample);
|
|
152
144
|
}
|
|
153
|
-
|
|
154
|
-
|
|
145
|
+
catch (e) {
|
|
146
|
+
skip(e, 'brush sample');
|
|
155
147
|
}
|
|
148
|
+
reader.offset = brushEnd;
|
|
156
149
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case 'desc': {
|
|
153
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
154
|
+
for (const [index, brush] of (desc.Brsh || []).entries()) {
|
|
155
|
+
try {
|
|
156
|
+
const parsed = parseBrush(brush);
|
|
157
|
+
brushes.push(parsed);
|
|
158
|
+
brushByPreset[index] = parsed;
|
|
165
159
|
}
|
|
166
|
-
|
|
167
|
-
|
|
160
|
+
catch (e) {
|
|
161
|
+
skip(e, `brush "${brush['Nm ']}"`);
|
|
168
162
|
}
|
|
169
163
|
}
|
|
170
|
-
|
|
171
|
-
throw new Error('Invalid depth');
|
|
172
|
-
}
|
|
173
|
-
samples.push({ id, bounds: { x, y, w, h }, alpha });
|
|
174
|
-
reader.offset = brushEnd;
|
|
164
|
+
break;
|
|
175
165
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// require('fs').writeFileSync('test.log', require('util').inspect(desc, false, 99, false), 'utf8');
|
|
182
|
-
for (const brush of desc.Brsh) {
|
|
183
|
-
const b = {
|
|
184
|
-
name: brush['Nm '],
|
|
185
|
-
shape: parseBrushShape(brush.Brsh),
|
|
186
|
-
spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
|
|
187
|
-
// TODO: brushGroup ???
|
|
188
|
-
wetEdges: brush.Wtdg,
|
|
189
|
-
noise: brush.Nose,
|
|
190
|
-
// TODO: TxtC ??? smoothing / build-up ?
|
|
191
|
-
// TODO: 'Rpt ' ???
|
|
192
|
-
useBrushSize: brush.useBrushSize, // ???
|
|
193
|
-
};
|
|
194
|
-
if (brush.interpretation != null)
|
|
195
|
-
b.interpretation = brush.interpretation;
|
|
196
|
-
if (brush.protectTexture != null)
|
|
197
|
-
b.protectTexture = brush.protectTexture;
|
|
198
|
-
if (brush.useTipDynamics) {
|
|
199
|
-
b.shapeDynamics = {
|
|
200
|
-
tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
|
|
201
|
-
sizeDynamics: parseDynamics(brush.szVr),
|
|
202
|
-
angleDynamics: parseDynamics(brush.angleDynamics),
|
|
203
|
-
roundnessDynamics: parseDynamics(brush.roundnessDynamics),
|
|
204
|
-
flipX: brush.flipX,
|
|
205
|
-
flipY: brush.flipY,
|
|
206
|
-
brushProjection: brush.brushProjection,
|
|
207
|
-
minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
|
|
208
|
-
minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
if (brush.useScatter) {
|
|
212
|
-
b.scatter = {
|
|
213
|
-
count: brush['Cnt '],
|
|
214
|
-
bothAxes: brush.bothAxes,
|
|
215
|
-
countDynamics: parseDynamics(brush.countDynamics),
|
|
216
|
-
scatterDynamics: parseDynamics(brush.scatterDynamics),
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
if (brush.useTexture && brush.Txtr) {
|
|
220
|
-
b.texture = {
|
|
221
|
-
id: brush.Txtr.Idnt,
|
|
222
|
-
name: brush.Txtr['Nm '],
|
|
223
|
-
blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
|
|
224
|
-
depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
|
|
225
|
-
depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
|
|
226
|
-
depthDynamics: parseDynamics(brush.textureDepthDynamics),
|
|
227
|
-
scale: (0, descriptor_1.parsePercent)(brush.textureScale),
|
|
228
|
-
invert: brush.InvT,
|
|
229
|
-
brightness: brush.textureBrightness,
|
|
230
|
-
contrast: brush.textureContrast,
|
|
231
|
-
textureEachTip: !!brush.TxtC,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
const db = brush.dualBrush;
|
|
235
|
-
if (db && db.useDualBrush) {
|
|
236
|
-
b.dualBrush = {
|
|
237
|
-
flip: db.Flip,
|
|
238
|
-
shape: parseBrushShape(db.Brsh),
|
|
239
|
-
blendMode: descriptor_1.BlnM.decode(db.BlnM),
|
|
240
|
-
useScatter: db.useScatter,
|
|
241
|
-
spacing: (0, descriptor_1.parsePercent)(db.Spcn),
|
|
242
|
-
count: db['Cnt '],
|
|
243
|
-
bothAxes: db.bothAxes,
|
|
244
|
-
countDynamics: parseDynamics(db.countDynamics),
|
|
245
|
-
scatterDynamics: parseDynamics(db.scatterDynamics),
|
|
246
|
-
};
|
|
166
|
+
case 'patt': {
|
|
167
|
+
while (reader.offset + 4 <= end) {
|
|
168
|
+
const pattern = (0, psdReader_1.readPatternSafe)(reader);
|
|
169
|
+
if (pattern)
|
|
170
|
+
patterns.push(pattern);
|
|
247
171
|
}
|
|
248
|
-
|
|
249
|
-
b.colorDynamics = {
|
|
250
|
-
foregroundBackground: parseDynamics(brush.clVr),
|
|
251
|
-
hue: (0, descriptor_1.parsePercent)(brush['H ']),
|
|
252
|
-
saturation: (0, descriptor_1.parsePercent)(brush.Strt),
|
|
253
|
-
brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
|
|
254
|
-
purity: (0, descriptor_1.parsePercent)(brush.purity),
|
|
255
|
-
perTip: brush.colorDynamicsPerTip,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
if (brush.usePaintDynamics) {
|
|
259
|
-
b.transfer = {
|
|
260
|
-
flowDynamics: parseDynamics(brush.prVr),
|
|
261
|
-
opacityDynamics: parseDynamics(brush.opVr),
|
|
262
|
-
wetnessDynamics: parseDynamics(brush.wtVr),
|
|
263
|
-
mixDynamics: parseDynamics(brush.mxVr),
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
if (brush.useBrushPose) {
|
|
267
|
-
b.brushPose = {
|
|
268
|
-
overrideAngle: brush.overridePoseAngle,
|
|
269
|
-
overrideTiltX: brush.overridePoseTiltX,
|
|
270
|
-
overrideTiltY: brush.overridePoseTiltY,
|
|
271
|
-
overridePressure: brush.overridePosePressure,
|
|
272
|
-
pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
|
|
273
|
-
tiltX: brush.brushPoseTiltX,
|
|
274
|
-
tiltY: brush.brushPoseTiltY,
|
|
275
|
-
angle: brush.brushPoseAngle,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
const to = brush.toolOptions;
|
|
279
|
-
if (to) {
|
|
280
|
-
b.toolOptions = {
|
|
281
|
-
type: toBrushType[to._classID] || 'brush',
|
|
282
|
-
brushPreset: to.brushPreset,
|
|
283
|
-
flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
|
|
284
|
-
smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
|
|
285
|
-
mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
|
|
286
|
-
opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
|
|
287
|
-
smoothing: !!to.smoothing,
|
|
288
|
-
smoothingValue: to.smoothingValue || 0,
|
|
289
|
-
smoothingRadiusMode: !!to.smoothingRadiusMode,
|
|
290
|
-
smoothingCatchup: !!to.smoothingCatchup,
|
|
291
|
-
smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
|
|
292
|
-
smoothingZoomCompensation: !!to.smoothingZoomCompensation,
|
|
293
|
-
pressureSmoothing: !!to.pressureSmoothing,
|
|
294
|
-
usePressureOverridesSize: !!to.usePressureOverridesSize,
|
|
295
|
-
usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
|
|
296
|
-
useLegacy: !!to.useLegacy,
|
|
297
|
-
};
|
|
298
|
-
if (to.prVr)
|
|
299
|
-
b.toolOptions.flowDynamics = parseDynamics(to.prVr);
|
|
300
|
-
if (to.opVr)
|
|
301
|
-
b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
|
|
302
|
-
if (to.szVr)
|
|
303
|
-
b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
|
|
304
|
-
if ('wetness' in to)
|
|
305
|
-
b.toolOptions.wetness = to.wetness;
|
|
306
|
-
if ('dryness' in to)
|
|
307
|
-
b.toolOptions.dryness = to.dryness;
|
|
308
|
-
if ('mix' in to)
|
|
309
|
-
b.toolOptions.mix = to.mix;
|
|
310
|
-
if ('autoFill' in to)
|
|
311
|
-
b.toolOptions.autoFill = to.autoFill;
|
|
312
|
-
if ('autoClean' in to)
|
|
313
|
-
b.toolOptions.autoClean = to.autoClean;
|
|
314
|
-
if ('loadSolidColorOnly' in to)
|
|
315
|
-
b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
|
|
316
|
-
if ('sampleAllLayers' in to)
|
|
317
|
-
b.toolOptions.sampleAllLayers = to.sampleAllLayers;
|
|
318
|
-
if ('SmdF' in to)
|
|
319
|
-
b.toolOptions.smudgeFingerPainting = to.SmdF;
|
|
320
|
-
if ('SmdS' in to)
|
|
321
|
-
b.toolOptions.smudgeSampleAllLayers = to.SmdS;
|
|
322
|
-
if ('Prs ' in to)
|
|
323
|
-
b.toolOptions.strength = to['Prs '];
|
|
324
|
-
}
|
|
325
|
-
brushes.push(b);
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
case 'patt': {
|
|
330
|
-
while (reader.offset < end) {
|
|
331
|
-
patterns.push((0, psdReader_1.readPattern)(reader));
|
|
172
|
+
break;
|
|
332
173
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
339
|
-
// example:
|
|
340
|
-
// hierarchy: [
|
|
341
|
-
// {
|
|
342
|
-
// 'Nm ': 'PRE_EXPORT ',
|
|
343
|
-
// zuid: '965209f2-6f35-9a40-aa43-485684382172'
|
|
344
|
-
// },
|
|
345
|
-
// {},
|
|
346
|
-
// ...
|
|
347
|
-
// ]
|
|
348
|
-
if (options.logMissingFeatures) {
|
|
349
|
-
if ((_d = desc.hierarchy) === null || _d === void 0 ? void 0 : _d.length) {
|
|
350
|
-
// console.log('unhandled phry section', desc);
|
|
351
|
-
}
|
|
174
|
+
case 'phry': { // brush groups (folders in brushes panel)
|
|
175
|
+
// flat list of group starts, presets (in the same order as in 'desc' section) and group ends
|
|
176
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
177
|
+
hierarchy = desc.hierarchy;
|
|
178
|
+
break;
|
|
352
179
|
}
|
|
353
|
-
|
|
180
|
+
default:
|
|
181
|
+
// 'lPdc' (tool presets) and other unknown sections
|
|
182
|
+
options.logMissingFeatures && reader.log(`Unhandled brush section: ${type}`);
|
|
183
|
+
break;
|
|
354
184
|
}
|
|
355
|
-
|
|
356
|
-
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
skip(e, `brush section ${type}`);
|
|
357
188
|
}
|
|
358
189
|
// skip any unread data in the section and align to 4 bytes
|
|
359
190
|
reader.offset = end;
|
|
@@ -364,8 +195,304 @@ function readAbr(buffer, options = {}) {
|
|
|
364
195
|
else {
|
|
365
196
|
throw new Error(`Unsupported ABR version (${version})`);
|
|
366
197
|
}
|
|
198
|
+
if (hierarchy) {
|
|
199
|
+
const groups = [];
|
|
200
|
+
let presetIndex = 0;
|
|
201
|
+
for (const item of hierarchy) {
|
|
202
|
+
if (item._classID === 'Grup') {
|
|
203
|
+
groups.push(item['Nm ']);
|
|
204
|
+
}
|
|
205
|
+
else if (item._classID === 'groupEnd') {
|
|
206
|
+
groups.pop();
|
|
207
|
+
}
|
|
208
|
+
else if (item._classID === 'preset') {
|
|
209
|
+
const brush = brushByPreset[presetIndex];
|
|
210
|
+
if (brush && groups.length)
|
|
211
|
+
brush.group = groups.slice();
|
|
212
|
+
presetIndex++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
367
216
|
return { samples, patterns, brushes };
|
|
368
217
|
}
|
|
218
|
+
function readSample(reader, brushEnd, minorVersion) {
|
|
219
|
+
const id = (0, psdReader_1.readPascalString)(reader, 1);
|
|
220
|
+
// v1 - Skip the Int16 bounds rectangle and the unknown Int16.
|
|
221
|
+
// v2 - Skip the unknown bytes.
|
|
222
|
+
(0, psdReader_1.skipBytes)(reader, minorVersion === 1 ? 10 : 264);
|
|
223
|
+
return readSampleBitmap(reader, brushEnd, id);
|
|
224
|
+
}
|
|
225
|
+
// bounds, bit depth, compression and image data of brush sample
|
|
226
|
+
function readSampleBitmap(reader, brushEnd, id) {
|
|
227
|
+
const y = (0, psdReader_1.readInt32)(reader);
|
|
228
|
+
const x = (0, psdReader_1.readInt32)(reader);
|
|
229
|
+
const h = (0, psdReader_1.readInt32)(reader) - y;
|
|
230
|
+
const w = (0, psdReader_1.readInt32)(reader) - x;
|
|
231
|
+
if (w <= 0 || h <= 0)
|
|
232
|
+
throw new Error('Invalid bounds');
|
|
233
|
+
if (w > MAX_BRUSH_SIZE || h > MAX_BRUSH_SIZE) {
|
|
234
|
+
throw new Error(`Brush sample too large (${w}x${h})`);
|
|
235
|
+
}
|
|
236
|
+
const bithDepth = (0, psdReader_1.readInt16)(reader);
|
|
237
|
+
const compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
|
|
238
|
+
if (bithDepth !== 8 && bithDepth !== 16)
|
|
239
|
+
throw new Error('Invalid depth');
|
|
240
|
+
if (compression !== 0 && compression !== 1)
|
|
241
|
+
throw new Error('Invalid compression');
|
|
242
|
+
const rowSize = w * (bithDepth === 16 ? 2 : 1);
|
|
243
|
+
// RLE needs at least 2 bytes for row length and 2 bytes per each 128 byte run
|
|
244
|
+
const minDataSize = compression === 0 ? h * rowSize : h * (2 + Math.ceil(rowSize / 128) * 2);
|
|
245
|
+
if (minDataSize > brushEnd - reader.offset) {
|
|
246
|
+
throw new Error('Brush sample data out of bounds');
|
|
247
|
+
}
|
|
248
|
+
(0, psdReader_1.consumeMemory)(reader, w * h * (compression === 1 && bithDepth === 16 ? 3 : 1));
|
|
249
|
+
const alpha = new Uint8Array(w * h);
|
|
250
|
+
if (bithDepth === 8) {
|
|
251
|
+
if (compression === 0) {
|
|
252
|
+
alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
|
|
253
|
+
}
|
|
254
|
+
else if (compression === 1) {
|
|
255
|
+
(0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
throw new Error('Invalid compression');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (bithDepth === 16) {
|
|
262
|
+
if (compression === 0) {
|
|
263
|
+
for (let i = 0; i < alpha.byteLength; i++) {
|
|
264
|
+
alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else if (compression === 1) {
|
|
268
|
+
const data = new Uint16Array(w * h);
|
|
269
|
+
(0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data }, w, h, bithDepth, 1, [0], false);
|
|
270
|
+
for (let i = 0; i < alpha.byteLength; i++) {
|
|
271
|
+
alpha[i] = data[i] >> 8; // convert to 8bit values
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
throw new Error('Invalid compression');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
throw new Error('Invalid depth');
|
|
280
|
+
}
|
|
281
|
+
return { id, bounds: { x, y, w, h }, alpha };
|
|
282
|
+
}
|
|
283
|
+
// ABR versions 1 and 2 (Photoshop 6 and earlier) contain a list of brushes with brush tips in them
|
|
284
|
+
function readLegacyBrushes(reader, version, samples, brushes, skip) {
|
|
285
|
+
const count = (0, psdReader_1.readUint16)(reader);
|
|
286
|
+
for (let i = 0; i < count; i++) {
|
|
287
|
+
const type = (0, psdReader_1.readUint16)(reader);
|
|
288
|
+
const size = (0, psdReader_1.readUint32)(reader);
|
|
289
|
+
const end = reader.offset + size;
|
|
290
|
+
if (end > reader.view.byteLength) { // truncated file
|
|
291
|
+
skip(new Error('Brush data out of bounds'), `brush ${i + 1}`);
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
if (type === 1) { // computed brush
|
|
296
|
+
(0, psdReader_1.skipBytes)(reader, 4); // misc
|
|
297
|
+
const spacing = (0, psdReader_1.readUint16)(reader);
|
|
298
|
+
const diameter = (0, psdReader_1.readUint16)(reader);
|
|
299
|
+
const roundness = (0, psdReader_1.readUint16)(reader);
|
|
300
|
+
const angle = (0, psdReader_1.readInt16)(reader);
|
|
301
|
+
const hardness = (0, psdReader_1.readUint16)(reader);
|
|
302
|
+
if (reader.offset > end)
|
|
303
|
+
throw new Error('Brush data out of bounds');
|
|
304
|
+
brushes.push(createLegacyBrush('', {
|
|
305
|
+
type: 'computed',
|
|
306
|
+
size: diameter,
|
|
307
|
+
angle,
|
|
308
|
+
roundness: roundness / 100,
|
|
309
|
+
spacingOn: spacing !== 0,
|
|
310
|
+
spacing: spacing / 100,
|
|
311
|
+
flipX: false,
|
|
312
|
+
flipY: false,
|
|
313
|
+
hardness: hardness / 100,
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
else if (type === 2) { // sampled brush
|
|
317
|
+
(0, psdReader_1.skipBytes)(reader, 4); // misc
|
|
318
|
+
const spacing = (0, psdReader_1.readUint16)(reader);
|
|
319
|
+
const name = version === 2 ? (0, psdReader_1.readUnicodeString)(reader) : '';
|
|
320
|
+
(0, psdReader_1.skipBytes)(reader, 1 + 8); // antialiasing, Int16 bounds rectangle (same as Int32 one)
|
|
321
|
+
// legacy brushes don't have sample ids
|
|
322
|
+
const sample = readSampleBitmap(reader, end, `brush-${i + 1}`);
|
|
323
|
+
samples.push(sample);
|
|
324
|
+
brushes.push(createLegacyBrush(name, {
|
|
325
|
+
type: 'sampled',
|
|
326
|
+
size: Math.max(sample.bounds.w, sample.bounds.h),
|
|
327
|
+
angle: 0,
|
|
328
|
+
roundness: 1,
|
|
329
|
+
spacingOn: spacing !== 0,
|
|
330
|
+
spacing: spacing / 100,
|
|
331
|
+
flipX: false,
|
|
332
|
+
flipY: false,
|
|
333
|
+
name,
|
|
334
|
+
sampledData: sample.id,
|
|
335
|
+
}));
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
throw new Error(`Unknown brush type: ${type}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch (e) {
|
|
342
|
+
skip(e, `brush ${i + 1}`);
|
|
343
|
+
}
|
|
344
|
+
reader.offset = end;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function createLegacyBrush(name, shape) {
|
|
348
|
+
return { name, shape, spacing: 1, wetEdges: false, noise: false, buildUp: false, useBrushSize: true };
|
|
349
|
+
}
|
|
350
|
+
function parseBrush(brush) {
|
|
351
|
+
var _a, _b, _c;
|
|
352
|
+
const b = {
|
|
353
|
+
name: brush['Nm '],
|
|
354
|
+
shape: parseBrushShape(brush.Brsh),
|
|
355
|
+
spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
|
|
356
|
+
wetEdges: brush.Wtdg,
|
|
357
|
+
noise: brush.Nose,
|
|
358
|
+
buildUp: !!brush['Rpt '],
|
|
359
|
+
useBrushSize: brush.useBrushSize, // ???
|
|
360
|
+
};
|
|
361
|
+
if (brush.interpretation != null)
|
|
362
|
+
b.interpretation = brush.interpretation;
|
|
363
|
+
if (brush.protectTexture != null)
|
|
364
|
+
b.protectTexture = brush.protectTexture;
|
|
365
|
+
if (brush.useTipDynamics) {
|
|
366
|
+
b.shapeDynamics = {
|
|
367
|
+
tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
|
|
368
|
+
sizeDynamics: parseDynamics(brush.szVr),
|
|
369
|
+
angleDynamics: parseDynamics(brush.angleDynamics),
|
|
370
|
+
roundnessDynamics: parseDynamics(brush.roundnessDynamics),
|
|
371
|
+
flipX: brush.flipX,
|
|
372
|
+
flipY: brush.flipY,
|
|
373
|
+
brushProjection: brush.brushProjection,
|
|
374
|
+
minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
|
|
375
|
+
minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
if (brush.useScatter) {
|
|
379
|
+
b.scatter = {
|
|
380
|
+
count: brush['Cnt '],
|
|
381
|
+
bothAxes: brush.bothAxes,
|
|
382
|
+
countDynamics: parseDynamics(brush.countDynamics),
|
|
383
|
+
scatterDynamics: parseDynamics(brush.scatterDynamics),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (brush.useTexture && brush.Txtr) {
|
|
387
|
+
b.texture = {
|
|
388
|
+
id: brush.Txtr.Idnt,
|
|
389
|
+
name: brush.Txtr['Nm '],
|
|
390
|
+
blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
|
|
391
|
+
depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
|
|
392
|
+
depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
|
|
393
|
+
depthDynamics: parseDynamics(brush.textureDepthDynamics),
|
|
394
|
+
scale: (0, descriptor_1.parsePercent)(brush.textureScale),
|
|
395
|
+
invert: brush.InvT,
|
|
396
|
+
brightness: brush.textureBrightness,
|
|
397
|
+
contrast: brush.textureContrast,
|
|
398
|
+
textureEachTip: !!brush.TxtC,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const db = brush.dualBrush;
|
|
402
|
+
if (db && db.useDualBrush) {
|
|
403
|
+
b.dualBrush = {
|
|
404
|
+
flip: db.Flip,
|
|
405
|
+
shape: parseBrushShape(db.Brsh),
|
|
406
|
+
blendMode: descriptor_1.BlnM.decode(db.BlnM),
|
|
407
|
+
useScatter: db.useScatter,
|
|
408
|
+
spacing: (0, descriptor_1.parsePercent)(db.Spcn),
|
|
409
|
+
count: db['Cnt '],
|
|
410
|
+
bothAxes: db.bothAxes,
|
|
411
|
+
countDynamics: parseDynamics(db.countDynamics),
|
|
412
|
+
scatterDynamics: parseDynamics(db.scatterDynamics),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (brush.useColorDynamics) {
|
|
416
|
+
b.colorDynamics = {
|
|
417
|
+
foregroundBackground: parseDynamics(brush.clVr),
|
|
418
|
+
hue: (0, descriptor_1.parsePercent)(brush['H ']),
|
|
419
|
+
saturation: (0, descriptor_1.parsePercent)(brush.Strt),
|
|
420
|
+
brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
|
|
421
|
+
purity: (0, descriptor_1.parsePercent)(brush.purity),
|
|
422
|
+
perTip: brush.colorDynamicsPerTip,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
if (brush.usePaintDynamics) {
|
|
426
|
+
b.transfer = {
|
|
427
|
+
flowDynamics: parseDynamics(brush.prVr),
|
|
428
|
+
opacityDynamics: parseDynamics(brush.opVr),
|
|
429
|
+
};
|
|
430
|
+
if (brush.wtVr)
|
|
431
|
+
b.transfer.wetnessDynamics = parseDynamics(brush.wtVr);
|
|
432
|
+
if (brush.mxVr)
|
|
433
|
+
b.transfer.mixDynamics = parseDynamics(brush.mxVr);
|
|
434
|
+
}
|
|
435
|
+
if (brush.useBrushPose) {
|
|
436
|
+
b.brushPose = {
|
|
437
|
+
overrideAngle: brush.overridePoseAngle,
|
|
438
|
+
overrideTiltX: brush.overridePoseTiltX,
|
|
439
|
+
overrideTiltY: brush.overridePoseTiltY,
|
|
440
|
+
overridePressure: brush.overridePosePressure,
|
|
441
|
+
pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
|
|
442
|
+
tiltX: brush.brushPoseTiltX,
|
|
443
|
+
tiltY: brush.brushPoseTiltY,
|
|
444
|
+
angle: brush.brushPoseAngle,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
const to = brush.toolOptions;
|
|
448
|
+
if (to) {
|
|
449
|
+
b.toolOptions = {
|
|
450
|
+
type: toBrushType[to._classID] || 'brush',
|
|
451
|
+
brushPreset: to.brushPreset,
|
|
452
|
+
flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
|
|
453
|
+
smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
|
|
454
|
+
mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'), // sometimes mode is missing
|
|
455
|
+
opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
|
|
456
|
+
smoothing: !!to.smoothing,
|
|
457
|
+
smoothingValue: to.smoothingValue || 0,
|
|
458
|
+
smoothingRadiusMode: !!to.smoothingRadiusMode,
|
|
459
|
+
smoothingCatchup: !!to.smoothingCatchup,
|
|
460
|
+
smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
|
|
461
|
+
smoothingZoomCompensation: !!to.smoothingZoomCompensation,
|
|
462
|
+
pressureSmoothing: !!to.pressureSmoothing,
|
|
463
|
+
usePressureOverridesSize: !!to.usePressureOverridesSize,
|
|
464
|
+
usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
|
|
465
|
+
useLegacy: !!to.useLegacy,
|
|
466
|
+
};
|
|
467
|
+
if (to.prVr)
|
|
468
|
+
b.toolOptions.flowDynamics = parseDynamics(to.prVr);
|
|
469
|
+
if (to.opVr)
|
|
470
|
+
b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
|
|
471
|
+
if (to.szVr)
|
|
472
|
+
b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
|
|
473
|
+
if ('wetness' in to)
|
|
474
|
+
b.toolOptions.wetness = to.wetness;
|
|
475
|
+
if ('dryness' in to)
|
|
476
|
+
b.toolOptions.dryness = to.dryness;
|
|
477
|
+
if ('mix' in to)
|
|
478
|
+
b.toolOptions.mix = to.mix;
|
|
479
|
+
if ('autoFill' in to)
|
|
480
|
+
b.toolOptions.autoFill = to.autoFill;
|
|
481
|
+
if ('autoClean' in to)
|
|
482
|
+
b.toolOptions.autoClean = to.autoClean;
|
|
483
|
+
if ('loadSolidColorOnly' in to)
|
|
484
|
+
b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
|
|
485
|
+
if ('sampleAllLayers' in to)
|
|
486
|
+
b.toolOptions.sampleAllLayers = to.sampleAllLayers;
|
|
487
|
+
if ('SmdF' in to)
|
|
488
|
+
b.toolOptions.smudgeFingerPainting = to.SmdF;
|
|
489
|
+
if ('SmdS' in to)
|
|
490
|
+
b.toolOptions.smudgeSampleAllLayers = to.SmdS;
|
|
491
|
+
if ('Prs ' in to)
|
|
492
|
+
b.toolOptions.strength = to['Prs '];
|
|
493
|
+
}
|
|
494
|
+
return b;
|
|
495
|
+
}
|
|
369
496
|
|
|
370
497
|
},{"./descriptor":4,"./psdReader":13}],2:[function(require,module,exports){
|
|
371
498
|
"use strict";
|
|
@@ -373,6 +500,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
373
500
|
exports.booleanOperations = exports.infoHandlersMap = exports.infoHandlers = void 0;
|
|
374
501
|
exports.readBezierKnot = readBezierKnot;
|
|
375
502
|
exports.readVectorMask = readVectorMask;
|
|
503
|
+
exports.writeVectorMask = writeVectorMask;
|
|
504
|
+
exports.parseKeyDescriptorList = parseKeyDescriptorList;
|
|
505
|
+
exports.serializeKeyDescriptorList = serializeKeyDescriptorList;
|
|
376
506
|
exports.hasMultiEffects = hasMultiEffects;
|
|
377
507
|
const base64_js_1 = require("base64-js");
|
|
378
508
|
const effectsHelpers_1 = require("./effectsHelpers");
|
|
@@ -403,6 +533,7 @@ function readLength64(reader) {
|
|
|
403
533
|
return (0, psdReader_1.readUint32)(reader);
|
|
404
534
|
}
|
|
405
535
|
addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
536
|
+
var _a;
|
|
406
537
|
if ((0, psdReader_1.readInt16)(reader) !== 1)
|
|
407
538
|
throw new Error(`Invalid TySh version`);
|
|
408
539
|
const transform = [];
|
|
@@ -449,7 +580,8 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
|
449
580
|
// require('fs').writeFileSync('before.txt', require('util').inspect(before, false, 99, false), 'utf8');
|
|
450
581
|
// require('fs').writeFileSync('after.txt', require('util').inspect(after, false, 99, false), 'utf8');
|
|
451
582
|
// console.log(require('util').inspect(parseEngineData(text.EngineData), false, 99, true));
|
|
452
|
-
|
|
583
|
+
// descriptor anti-alias value is more reliable than the one from engine data
|
|
584
|
+
target.text = Object.assign(Object.assign(Object.assign({}, target.text), textData), { antiAlias: (_a = target.text.antiAlias) !== null && _a !== void 0 ? _a : textData.antiAlias });
|
|
453
585
|
// console.log(require('util').inspect(target.text, false, 99, true));
|
|
454
586
|
}
|
|
455
587
|
(0, psdReader_1.skipBytes)(reader, leftBytes());
|
|
@@ -579,25 +711,8 @@ function readVectorMask(reader, vectorMask, width, height, size) {
|
|
|
579
711
|
}
|
|
580
712
|
return paths;
|
|
581
713
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
throw new Error('Invalid vmsk version');
|
|
585
|
-
target.vectorMask = { paths: [] };
|
|
586
|
-
const vectorMask = target.vectorMask;
|
|
587
|
-
const flags = (0, psdReader_1.readUint32)(reader);
|
|
588
|
-
vectorMask.invert = (flags & 1) !== 0;
|
|
589
|
-
vectorMask.notLink = (flags & 2) !== 0;
|
|
590
|
-
vectorMask.disable = (flags & 4) !== 0;
|
|
591
|
-
readVectorMask(reader, vectorMask, width, height, left());
|
|
592
|
-
// drawBezierPaths(vectorMask.paths, width, height, 'out.png');
|
|
593
|
-
(0, psdReader_1.skipBytes)(reader, left());
|
|
594
|
-
}, (writer, target, { width, height }) => {
|
|
595
|
-
const vectorMask = target.vectorMask;
|
|
596
|
-
const flags = (vectorMask.invert ? 1 : 0) |
|
|
597
|
-
(vectorMask.notLink ? 2 : 0) |
|
|
598
|
-
(vectorMask.disable ? 4 : 0);
|
|
599
|
-
(0, psdWriter_1.writeUint32)(writer, 3); // version
|
|
600
|
-
(0, psdWriter_1.writeUint32)(writer, flags);
|
|
714
|
+
// componentIndices - write index of path component for each subpath (Photoshop writes them for layer vector masks)
|
|
715
|
+
function writeVectorMask(writer, vectorMask, width, height, componentIndices = false) {
|
|
601
716
|
// initial entry
|
|
602
717
|
(0, psdWriter_1.writeUint16)(writer, 6);
|
|
603
718
|
(0, psdWriter_1.writeZeros)(writer, 24);
|
|
@@ -614,12 +729,18 @@ addHandler('vmsk', hasKey('vectorMask'), (reader, target, left, { width, height
|
|
|
614
729
|
(0, psdWriter_1.writeUint16)(writer, 8);
|
|
615
730
|
(0, psdWriter_1.writeUint16)(writer, vectorMask.fillStartsWithAllPixels ? 1 : 0);
|
|
616
731
|
(0, psdWriter_1.writeZeros)(writer, 22);
|
|
732
|
+
let componentIndex = -1;
|
|
617
733
|
for (const path of vectorMask.paths) {
|
|
734
|
+
// subpaths without operation are part of the same path component as previous subpath
|
|
735
|
+
if (path.operation || componentIndex < 0)
|
|
736
|
+
componentIndex++;
|
|
618
737
|
(0, psdWriter_1.writeUint16)(writer, path.open ? 3 : 0);
|
|
619
738
|
(0, psdWriter_1.writeUint16)(writer, path.knots.length);
|
|
620
739
|
(0, psdWriter_1.writeUint16)(writer, path.operation ? exports.booleanOperations.indexOf(path.operation) : -1); // -1 for undefined
|
|
621
740
|
(0, psdWriter_1.writeUint16)(writer, path.fillRule === 'non-zero' ? 2 : 1);
|
|
622
|
-
(0, psdWriter_1.writeZeros)(writer,
|
|
741
|
+
(0, psdWriter_1.writeZeros)(writer, 4);
|
|
742
|
+
(0, psdWriter_1.writeUint32)(writer, componentIndices ? componentIndex : 0);
|
|
743
|
+
(0, psdWriter_1.writeZeros)(writer, 10);
|
|
623
744
|
const linkedKnot = path.open ? 4 : 1;
|
|
624
745
|
const unlinkedKnot = path.open ? 5 : 2;
|
|
625
746
|
for (const { linked, points } of path.knots) {
|
|
@@ -627,8 +748,29 @@ addHandler('vmsk', hasKey('vectorMask'), (reader, target, left, { width, height
|
|
|
627
748
|
writeBezierKnot(writer, points, width, height);
|
|
628
749
|
}
|
|
629
750
|
}
|
|
751
|
+
}
|
|
752
|
+
addHandler('vmsk', hasKey('vectorMask'), (reader, target, left, { width, height }) => {
|
|
753
|
+
if ((0, psdReader_1.readUint32)(reader) !== 3)
|
|
754
|
+
throw new Error('Invalid vmsk version');
|
|
755
|
+
target.vectorMask = { paths: [] };
|
|
756
|
+
const vectorMask = target.vectorMask;
|
|
757
|
+
const flags = (0, psdReader_1.readUint32)(reader);
|
|
758
|
+
vectorMask.invert = (flags & 1) !== 0;
|
|
759
|
+
vectorMask.notLink = (flags & 2) !== 0;
|
|
760
|
+
vectorMask.disable = (flags & 4) !== 0;
|
|
761
|
+
readVectorMask(reader, vectorMask, width, height, left());
|
|
762
|
+
// drawBezierPaths(vectorMask.paths, width, height, 'out.png');
|
|
763
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
764
|
+
}, (writer, target, { width, height }) => {
|
|
765
|
+
const vectorMask = target.vectorMask;
|
|
766
|
+
const flags = (vectorMask.invert ? 1 : 0) |
|
|
767
|
+
(vectorMask.notLink ? 2 : 0) |
|
|
768
|
+
(vectorMask.disable ? 4 : 0);
|
|
769
|
+
(0, psdWriter_1.writeUint32)(writer, 3); // version
|
|
770
|
+
(0, psdWriter_1.writeUint32)(writer, flags);
|
|
771
|
+
writeVectorMask(writer, vectorMask, width, height, true);
|
|
630
772
|
});
|
|
631
|
-
//
|
|
773
|
+
// written instead of 'vmsk' for layers with vector stroke ('vscg' section)
|
|
632
774
|
addHandlerAlias('vsms', 'vmsk');
|
|
633
775
|
// addHandlerAlias('vmsk', 'vsms');
|
|
634
776
|
addHandler('vowv', // something with vectors?
|
|
@@ -637,12 +779,8 @@ hasKey('vowv'), (reader, target) => {
|
|
|
637
779
|
}, (writer, target) => {
|
|
638
780
|
(0, psdWriter_1.writeUint32)(writer, target.vowv);
|
|
639
781
|
});
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
throw new Error(`Invalid vogk version`);
|
|
643
|
-
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
644
|
-
// console.log(require('util').inspect(desc, false, 99, true));
|
|
645
|
-
target.vectorOrigination = { keyDescriptorList: [] };
|
|
782
|
+
function parseKeyDescriptorList(desc) {
|
|
783
|
+
const keyDescriptorList = [];
|
|
646
784
|
for (const i of desc.keyDescriptorList) {
|
|
647
785
|
const item = {};
|
|
648
786
|
if (i.keyShapeInvalidated != null)
|
|
@@ -681,15 +819,14 @@ addHandler('vogk', hasKey('vectorOrigination'), (reader, target, left) => {
|
|
|
681
819
|
if (trnf) {
|
|
682
820
|
item.transform = [trnf.xx, trnf.xy, trnf.yx, trnf.yy, trnf.tx, trnf.ty];
|
|
683
821
|
}
|
|
684
|
-
|
|
822
|
+
keyDescriptorList.push(item);
|
|
685
823
|
}
|
|
686
|
-
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
const orig = target.vectorOrigination;
|
|
824
|
+
return keyDescriptorList;
|
|
825
|
+
}
|
|
826
|
+
function serializeKeyDescriptorList(keyDescriptorList) {
|
|
690
827
|
const desc = { keyDescriptorList: [] };
|
|
691
|
-
for (let i = 0; i <
|
|
692
|
-
const item =
|
|
828
|
+
for (let i = 0; i < keyDescriptorList.length; i++) {
|
|
829
|
+
const item = keyDescriptorList[i];
|
|
693
830
|
desc.keyDescriptorList.push({}); // we're adding keyOriginIndex at the end
|
|
694
831
|
const out = desc.keyDescriptorList[desc.keyDescriptorList.length - 1];
|
|
695
832
|
if (item.keyOriginType != null)
|
|
@@ -740,10 +877,21 @@ addHandler('vogk', hasKey('vectorOrigination'), (reader, target, left) => {
|
|
|
740
877
|
out.keyShapeInvalidated = item.keyShapeInvalidated;
|
|
741
878
|
out.keyOriginIndex = i;
|
|
742
879
|
}
|
|
880
|
+
return desc;
|
|
881
|
+
}
|
|
882
|
+
addHandler('vogk', hasKey('vectorOrigination'), (reader, target, left) => {
|
|
883
|
+
if ((0, psdReader_1.readInt32)(reader) !== 1)
|
|
884
|
+
throw new Error(`Invalid vogk version`);
|
|
885
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
886
|
+
// console.log(require('util').inspect(desc, false, 99, true));
|
|
887
|
+
target.vectorOrigination = { keyDescriptorList: parseKeyDescriptorList(desc) };
|
|
888
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
889
|
+
}, (writer, target) => {
|
|
890
|
+
const desc = serializeKeyDescriptorList(target.vectorOrigination.keyDescriptorList);
|
|
743
891
|
(0, psdWriter_1.writeInt32)(writer, 1); // version
|
|
744
892
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
745
893
|
});
|
|
746
|
-
addHandler('lmfx', target => target.effects !== undefined && hasMultiEffects(target.effects), (reader, target, left) => {
|
|
894
|
+
addHandler('lmfx', target => target.effects !== undefined && !isGroupLayer(target) && hasMultiEffects(target.effects), (reader, target, left) => {
|
|
747
895
|
const version = (0, psdReader_1.readUint32)(reader);
|
|
748
896
|
if (version !== 0)
|
|
749
897
|
throw new Error('Invalid lmfx version');
|
|
@@ -819,8 +967,12 @@ addHandler('lyid', target => target.id !== undefined || layerNeedsId(target), (r
|
|
|
819
967
|
let id;
|
|
820
968
|
if (target.id !== undefined) {
|
|
821
969
|
id = target.id;
|
|
822
|
-
|
|
823
|
-
|
|
970
|
+
if (options.layerIds.has(id)) {
|
|
971
|
+
// make sure we don't have duplicate layer ids (and don't take id explicitly set on another layer)
|
|
972
|
+
const explicitIds = getExplicitLayerIds(psd, options);
|
|
973
|
+
while (options.layerIds.has(id) || explicitIds.has(id))
|
|
974
|
+
id += 100;
|
|
975
|
+
}
|
|
824
976
|
}
|
|
825
977
|
else {
|
|
826
978
|
// generate id for layers that don't have it, if it's referenced by other sections
|
|
@@ -893,12 +1045,15 @@ addHandler('lspf', hasKey('protected'), (reader, target) => {
|
|
|
893
1045
|
};
|
|
894
1046
|
if (flags & 0x08)
|
|
895
1047
|
target.protected.artboards = true;
|
|
1048
|
+
if (flags & 0x80000000)
|
|
1049
|
+
target.protected.all = true;
|
|
896
1050
|
}, (writer, target) => {
|
|
897
1051
|
const flags = (target.protected.transparency ? 0x01 : 0) |
|
|
898
1052
|
(target.protected.composite ? 0x02 : 0) |
|
|
899
1053
|
(target.protected.position ? 0x04 : 0) |
|
|
900
|
-
(target.protected.artboards ? 0x08 : 0)
|
|
901
|
-
|
|
1054
|
+
(target.protected.artboards ? 0x08 : 0) |
|
|
1055
|
+
(target.protected.all ? 0x80000000 : 0);
|
|
1056
|
+
(0, psdWriter_1.writeUint32)(writer, flags >>> 0);
|
|
902
1057
|
});
|
|
903
1058
|
addHandler('lclr', hasKey('layerColor'), (reader, target) => {
|
|
904
1059
|
const color = (0, psdReader_1.readUint16)(reader);
|
|
@@ -909,106 +1064,160 @@ addHandler('lclr', hasKey('layerColor'), (reader, target) => {
|
|
|
909
1064
|
(0, psdWriter_1.writeUint16)(writer, index === -1 ? 0 : index);
|
|
910
1065
|
(0, psdWriter_1.writeZeros)(writer, 6);
|
|
911
1066
|
});
|
|
1067
|
+
function parseGeneratorSettings(settings) {
|
|
1068
|
+
const result = {};
|
|
1069
|
+
if (settings.exportAs) {
|
|
1070
|
+
result.exportAs = {};
|
|
1071
|
+
if (settings.exportAs.exportOption !== undefined)
|
|
1072
|
+
result.exportAs.exportOption = settings.exportAs.exportOption;
|
|
1073
|
+
if (settings.exportAs.scaleSettings !== undefined)
|
|
1074
|
+
result.exportAs.scaleSettings = settings.exportAs.scaleSettings;
|
|
1075
|
+
}
|
|
1076
|
+
if (settings.generator_45_assets)
|
|
1077
|
+
result.assets = settings.generator_45_assets.json;
|
|
1078
|
+
if (settings.layerTime !== undefined)
|
|
1079
|
+
result.layerTime = settings.layerTime;
|
|
1080
|
+
if (settings.crema)
|
|
1081
|
+
result.crema = settings.crema.json;
|
|
1082
|
+
return result;
|
|
1083
|
+
}
|
|
1084
|
+
function serializeGeneratorSettings(generatorSettings) {
|
|
1085
|
+
const settings = {
|
|
1086
|
+
_name: '',
|
|
1087
|
+
_classID: generatorSettings.assets !== undefined ? 'generatorSettings' : 'null',
|
|
1088
|
+
};
|
|
1089
|
+
if (generatorSettings.exportAs) {
|
|
1090
|
+
settings.exportAs = { _name: '', _classID: 'null' };
|
|
1091
|
+
if (generatorSettings.exportAs.exportOption !== undefined)
|
|
1092
|
+
settings.exportAs.exportOption = generatorSettings.exportAs.exportOption;
|
|
1093
|
+
if (generatorSettings.exportAs.scaleSettings !== undefined)
|
|
1094
|
+
settings.exportAs.scaleSettings = generatorSettings.exportAs.scaleSettings;
|
|
1095
|
+
}
|
|
1096
|
+
if (generatorSettings.assets !== undefined)
|
|
1097
|
+
settings.generator_45_assets = { _name: '', _classID: 'generatorSettings', json: generatorSettings.assets };
|
|
1098
|
+
if (generatorSettings.layerTime !== undefined)
|
|
1099
|
+
settings.layerTime = generatorSettings.layerTime;
|
|
1100
|
+
if (generatorSettings.crema !== undefined)
|
|
1101
|
+
settings.crema = { _name: '', _classID: 'null', json: generatorSettings.crema };
|
|
1102
|
+
return { generatorSettings: settings };
|
|
1103
|
+
}
|
|
1104
|
+
// document (Psd object) stores generator settings in 'extn' section instead of 'shmd' section
|
|
1105
|
+
function isDocument(target) {
|
|
1106
|
+
return target.width !== undefined;
|
|
1107
|
+
}
|
|
912
1108
|
addHandler('shmd', // Metadata setting
|
|
913
1109
|
// Metadata setting
|
|
914
|
-
target => target.timestamp !== undefined || target.animationFrames !== undefined || target.animationFrameFlags !== undefined || target.timeline !== undefined || target.comps !== undefined
|
|
1110
|
+
target => target.timestamp !== undefined || target.animationFrames !== undefined || target.animationFrameFlags !== undefined || target.timeline !== undefined || target.comps !== undefined ||
|
|
1111
|
+
(target.generatorSettings !== undefined && !isDocument(target)), (reader, target, left) => {
|
|
915
1112
|
const count = (0, psdReader_1.readUint32)(reader);
|
|
916
1113
|
for (let i = 0; i < count; i++) {
|
|
917
|
-
(0, psdReader_1.
|
|
1114
|
+
const signature = (0, psdReader_1.readSignature)(reader);
|
|
1115
|
+
if (signature !== '8BIM' && signature !== '8ELE')
|
|
1116
|
+
throw new Error(`Invalid shmd signature: '${signature}'`); // 8ELE in Photoshop Elements
|
|
918
1117
|
const key = (0, psdReader_1.readSignature)(reader);
|
|
919
1118
|
(0, psdReader_1.readUint8)(reader); // copy
|
|
920
1119
|
(0, psdReader_1.skipBytes)(reader, 3);
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
target.
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
930
|
-
// console.log('mlst', target.name, require('util').inspect(desc, false, 99, true));
|
|
931
|
-
target.animationFrames = [];
|
|
932
|
-
for (let i = 0; i < desc.LaSt.length; i++) {
|
|
933
|
-
const f = desc.LaSt[i];
|
|
934
|
-
const frame = { frames: f.FrLs };
|
|
935
|
-
if (f.enab !== undefined)
|
|
936
|
-
frame.enable = f.enab;
|
|
937
|
-
if (f.Ofst)
|
|
938
|
-
frame.offset = (0, descriptor_1.horzVrtcToXY)(f.Ofst);
|
|
939
|
-
if (f.FXRf)
|
|
940
|
-
frame.referencePoint = (0, descriptor_1.horzVrtcToXY)(f.FXRf);
|
|
941
|
-
if (f.Lefx)
|
|
942
|
-
frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, !!reader.logMissingFeatures);
|
|
943
|
-
if (f.blendOptions && f.blendOptions.Opct)
|
|
944
|
-
frame.opacity = (0, descriptor_1.parsePercent)(f.blendOptions.Opct);
|
|
945
|
-
target.animationFrames.push(frame);
|
|
1120
|
+
const end = reader.offset + 4 + reader.view.getUint32(reader.offset);
|
|
1121
|
+
try {
|
|
1122
|
+
(0, psdReader_1.readSection)(reader, 1, left => {
|
|
1123
|
+
if (key === 'cust') {
|
|
1124
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
1125
|
+
// console.log('cust', target.name, require('util').inspect(desc, false, 99, true));
|
|
1126
|
+
if (desc.layerTime !== undefined)
|
|
1127
|
+
target.timestamp = desc.layerTime;
|
|
946
1128
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
duration: (0, descriptor_1.frac)(timeScope.duration),
|
|
967
|
-
inTime: (0, descriptor_1.frac)(timeScope.inTime),
|
|
968
|
-
outTime: (0, descriptor_1.frac)(timeScope.outTime),
|
|
969
|
-
autoScope: desc.autoScope,
|
|
970
|
-
audioLevel: desc.audioLevel,
|
|
971
|
-
};
|
|
972
|
-
if (desc.trackList) {
|
|
973
|
-
timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, !!reader.logMissingFeatures);
|
|
1129
|
+
else if (key === 'mlst') {
|
|
1130
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
1131
|
+
// console.log('mlst', target.name, require('util').inspect(desc, false, 99, true));
|
|
1132
|
+
target.animationFrames = [];
|
|
1133
|
+
for (let i = 0; i < desc.LaSt.length; i++) {
|
|
1134
|
+
const f = desc.LaSt[i];
|
|
1135
|
+
const frame = { frames: f.FrLs };
|
|
1136
|
+
if (f.enab !== undefined)
|
|
1137
|
+
frame.enable = f.enab;
|
|
1138
|
+
if (f.Ofst)
|
|
1139
|
+
frame.offset = (0, descriptor_1.horzVrtcToXY)(f.Ofst);
|
|
1140
|
+
if (f.FXRf)
|
|
1141
|
+
frame.referencePoint = (0, descriptor_1.horzVrtcToXY)(f.FXRf);
|
|
1142
|
+
if (f.Lefx)
|
|
1143
|
+
frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, !!reader.logMissingFeatures);
|
|
1144
|
+
if (f.blendOptions && f.blendOptions.Opct)
|
|
1145
|
+
frame.opacity = (0, descriptor_1.parsePercent)(f.blendOptions.Opct);
|
|
1146
|
+
target.animationFrames.push(frame);
|
|
1147
|
+
}
|
|
974
1148
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
for (const item of desc.layerSettings) {
|
|
987
|
-
target.comps.settings.push({ compList: item.compList });
|
|
988
|
-
const t = target.comps.settings[target.comps.settings.length - 1];
|
|
989
|
-
if ('enab' in item)
|
|
990
|
-
t.enabled = item.enab;
|
|
991
|
-
if (item.Ofst)
|
|
992
|
-
t.offset = { x: item.Ofst.Hrzn, y: item.Ofst.Vrtc };
|
|
993
|
-
if (item.FXRefPoint)
|
|
994
|
-
t.effectsReferencePoint = { x: item.FXRefPoint.Hrzn, y: item.FXRefPoint.Vrtc };
|
|
1149
|
+
else if (key === 'mdyn') {
|
|
1150
|
+
// frame flags
|
|
1151
|
+
(0, psdReader_1.readUint16)(reader); // unknown
|
|
1152
|
+
const propagate = (0, psdReader_1.readUint8)(reader);
|
|
1153
|
+
const flags = (0, psdReader_1.readUint8)(reader);
|
|
1154
|
+
target.animationFrameFlags = {
|
|
1155
|
+
propagateFrameOne: !propagate,
|
|
1156
|
+
unifyLayerPosition: (flags & 1) !== 0,
|
|
1157
|
+
unifyLayerStyle: (flags & 2) !== 0,
|
|
1158
|
+
unifyLayerVisibility: (flags & 4) !== 0,
|
|
1159
|
+
};
|
|
995
1160
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1161
|
+
else if (key === 'tmln') {
|
|
1162
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
1163
|
+
const timeScope = desc.timeScope;
|
|
1164
|
+
// console.log('tmln', target.name, target.id, require('util').inspect(desc, false, 99, true));
|
|
1165
|
+
const timeline = {
|
|
1166
|
+
start: (0, descriptor_1.frac)(timeScope.Strt),
|
|
1167
|
+
duration: (0, descriptor_1.frac)(timeScope.duration),
|
|
1168
|
+
inTime: (0, descriptor_1.frac)(timeScope.inTime),
|
|
1169
|
+
outTime: (0, descriptor_1.frac)(timeScope.outTime),
|
|
1170
|
+
autoScope: desc.autoScope,
|
|
1171
|
+
audioLevel: desc.audioLevel,
|
|
1172
|
+
};
|
|
1173
|
+
if (desc.trackList) {
|
|
1174
|
+
timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, !!reader.logMissingFeatures);
|
|
1175
|
+
}
|
|
1176
|
+
target.timeline = timeline;
|
|
1177
|
+
// console.log('tmln:result', target.name, target.id, require('util').inspect(timeline, false, 99, true));
|
|
1178
|
+
}
|
|
1179
|
+
else if (key === 'cmls') {
|
|
1180
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
1181
|
+
// console.log('cmls', require('util').inspect(desc, false, 99, true));
|
|
1182
|
+
target.comps = {
|
|
1183
|
+
settings: [],
|
|
1184
|
+
};
|
|
1185
|
+
if (desc.origFXRefPoint)
|
|
1186
|
+
target.comps.originalEffectsReferencePoint = { x: desc.origFXRefPoint.Hrzn, y: desc.origFXRefPoint.Vrtc };
|
|
1187
|
+
for (const item of desc.layerSettings) {
|
|
1188
|
+
target.comps.settings.push({ compList: item.compList });
|
|
1189
|
+
const t = target.comps.settings[target.comps.settings.length - 1];
|
|
1190
|
+
if ('enab' in item)
|
|
1191
|
+
t.enabled = item.enab;
|
|
1192
|
+
if (item.Ofst)
|
|
1193
|
+
t.offset = { x: item.Ofst.Hrzn, y: item.Ofst.Vrtc };
|
|
1194
|
+
if (item.FXRefPoint)
|
|
1195
|
+
t.effectsReferencePoint = { x: item.FXRefPoint.Hrzn, y: item.FXRefPoint.Vrtc };
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
else if (key === 'extn') {
|
|
1199
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
1200
|
+
if (desc.generatorSettings)
|
|
1201
|
+
target.generatorSettings = parseGeneratorSettings(desc.generatorSettings);
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
reader.logMissingFeatures && reader.log('Unhandled "shmd" section key', key);
|
|
1205
|
+
}
|
|
1206
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
catch (e) {
|
|
1210
|
+
// failure to read one item shouldn't drop all other items
|
|
1211
|
+
if (reader.throwForMissingFeatures)
|
|
1212
|
+
throw e;
|
|
1213
|
+
reader.logMissingFeatures && reader.log(`Failed to read "shmd" section key ${key}: ${e.message}`);
|
|
1214
|
+
reader.offset = end;
|
|
1215
|
+
}
|
|
1008
1216
|
}
|
|
1009
1217
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
1010
1218
|
}, (writer, target, _, options) => {
|
|
1011
1219
|
const { animationFrames, animationFrameFlags, timestamp, timeline, comps } = target;
|
|
1220
|
+
const generatorSettings = isDocument(target) ? undefined : target.generatorSettings;
|
|
1012
1221
|
let count = 0;
|
|
1013
1222
|
if (animationFrames)
|
|
1014
1223
|
count++;
|
|
@@ -1020,6 +1229,8 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1020
1229
|
count++;
|
|
1021
1230
|
if (comps)
|
|
1022
1231
|
count++;
|
|
1232
|
+
if (generatorSettings)
|
|
1233
|
+
count++;
|
|
1023
1234
|
(0, psdWriter_1.writeUint32)(writer, count);
|
|
1024
1235
|
if (animationFrames) {
|
|
1025
1236
|
(0, psdWriter_1.writeSignature)(writer, '8BIM');
|
|
@@ -1042,9 +1253,9 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1042
1253
|
if (f.referencePoint)
|
|
1043
1254
|
frame.FXRf = (0, descriptor_1.xyToHorzVrtc)(f.referencePoint);
|
|
1044
1255
|
if (f.effects)
|
|
1045
|
-
frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, false,
|
|
1256
|
+
frame.Lefx = (0, descriptor_1.serializeEffects)(f.effects, false, hasMultiEffects(f.effects));
|
|
1046
1257
|
if (f.opacity !== undefined)
|
|
1047
|
-
frame.blendOptions = { Opct: (0, descriptor_1.
|
|
1258
|
+
frame.blendOptions = { Opct: (0, descriptor_1.unitsPercentF)(f.opacity) };
|
|
1048
1259
|
desc.LaSt.push(frame);
|
|
1049
1260
|
}
|
|
1050
1261
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
@@ -1128,6 +1339,15 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1128
1339
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
1129
1340
|
}, true);
|
|
1130
1341
|
}
|
|
1342
|
+
if (generatorSettings) {
|
|
1343
|
+
(0, psdWriter_1.writeSignature)(writer, '8BIM');
|
|
1344
|
+
(0, psdWriter_1.writeSignature)(writer, 'extn');
|
|
1345
|
+
(0, psdWriter_1.writeUint8)(writer, 0); // copy (always false)
|
|
1346
|
+
(0, psdWriter_1.writeZeros)(writer, 3);
|
|
1347
|
+
(0, psdWriter_1.writeSection)(writer, 2, () => {
|
|
1348
|
+
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', serializeGeneratorSettings(generatorSettings));
|
|
1349
|
+
}, true);
|
|
1350
|
+
}
|
|
1131
1351
|
});
|
|
1132
1352
|
addHandler('PxSc', hasKey('pixelSource'), (reader, target) => {
|
|
1133
1353
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
@@ -1207,7 +1427,7 @@ addHandler('vstk', hasKey('vectorStroke'), (reader, target, left) => {
|
|
|
1207
1427
|
lineAlignment: descriptor_1.strokeStyleLineAlignment.decode(desc.strokeStyleLineAlignment),
|
|
1208
1428
|
scaleLock: desc.strokeStyleScaleLock,
|
|
1209
1429
|
strokeAdjust: desc.strokeStyleStrokeAdjust,
|
|
1210
|
-
lineDashSet: desc.strokeStyleLineDashSet.map(descriptor_1.parseUnits),
|
|
1430
|
+
lineDashSet: (desc.strokeStyleLineDashSet || []).map(descriptor_1.parseUnits),
|
|
1211
1431
|
blendMode: descriptor_1.BlnM.decode(desc.strokeStyleBlendMode),
|
|
1212
1432
|
opacity: (0, descriptor_1.parsePercent)(desc.strokeStyleOpacity),
|
|
1213
1433
|
content: (0, descriptor_1.parseVectorContent)(desc.strokeStyleContent),
|
|
@@ -1245,9 +1465,11 @@ hasKey('artboard'), (reader, target, left) => {
|
|
|
1245
1465
|
rect: { top: rect['Top '], left: rect.Left, bottom: rect.Btom, right: rect.Rght },
|
|
1246
1466
|
guideIndices: desc.guideIndeces,
|
|
1247
1467
|
presetName: desc.artboardPresetName,
|
|
1248
|
-
color: (0, descriptor_1.parseColor)(desc['Clr ']),
|
|
1249
|
-
backgroundType: desc.artboardBackgroundType,
|
|
1250
1468
|
};
|
|
1469
|
+
if (desc['Clr '])
|
|
1470
|
+
target.artboard.color = (0, descriptor_1.parseColor)(desc['Clr ']);
|
|
1471
|
+
if (desc.artboardBackgroundType !== undefined)
|
|
1472
|
+
target.artboard.backgroundType = desc.artboardBackgroundType;
|
|
1251
1473
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
1252
1474
|
}, (writer, target) => {
|
|
1253
1475
|
var _a;
|
|
@@ -1353,14 +1575,15 @@ function encodeWarp(warp) {
|
|
|
1353
1575
|
}
|
|
1354
1576
|
return desc;
|
|
1355
1577
|
}
|
|
1356
|
-
addHandler('PlLd',
|
|
1578
|
+
addHandler('PlLd', target => !!target.placedLayer && !target.placedLayer.external, // linked smart objects are stored in SoLE
|
|
1579
|
+
(reader, target, left) => {
|
|
1357
1580
|
if ((0, psdReader_1.readSignature)(reader) !== 'plcL')
|
|
1358
1581
|
throw new Error(`Invalid PlLd signature`);
|
|
1359
1582
|
if ((0, psdReader_1.readInt32)(reader) !== 3)
|
|
1360
1583
|
throw new Error(`Invalid PlLd version`);
|
|
1361
1584
|
const id = (0, psdReader_1.readPascalString)(reader, 1);
|
|
1362
1585
|
const pageNumber = (0, psdReader_1.readInt32)(reader);
|
|
1363
|
-
const totalPages = (0, psdReader_1.readInt32)(reader); //
|
|
1586
|
+
const totalPages = (0, psdReader_1.readInt32)(reader); // for multi-page documents (PDF)
|
|
1364
1587
|
(0, psdReader_1.readInt32)(reader); // anitAliasPolicy 16
|
|
1365
1588
|
const placedLayerType = (0, psdReader_1.readInt32)(reader); // 0 = unknown, 1 = vector, 2 = raster, 3 = image stack
|
|
1366
1589
|
if (!placedLayerTypes[placedLayerType])
|
|
@@ -1405,6 +1628,8 @@ addHandler('PlLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
1405
1628
|
const type = isQuilt ? 'quiltWarp' : 'warp';
|
|
1406
1629
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', type, encodeWarp(warp), type);
|
|
1407
1630
|
});
|
|
1631
|
+
const levelsFilterKeys = ['_name', '_classID', 'presetKind', 'Adjs'];
|
|
1632
|
+
const levelsFilterAdjustmentKeys = ['_name', '_classID', 'Chnl', 'Inpt', 'Otpt', 'Gmm '];
|
|
1408
1633
|
function uint8ToFloat32(array) {
|
|
1409
1634
|
const length = Math.floor(array.byteLength / 4);
|
|
1410
1635
|
return new Float32Array(array.buffer.slice(array.byteOffset, array.byteOffset + length * 4), 0, length);
|
|
@@ -1447,7 +1672,7 @@ function pointToHrznVrtc(point) {
|
|
|
1447
1672
|
Vrtc: (0, descriptor_1.unitsValue)(point.y, 'y'),
|
|
1448
1673
|
};
|
|
1449
1674
|
}
|
|
1450
|
-
function parseFilterFXItem(f,
|
|
1675
|
+
function parseFilterFXItem(f, reader) {
|
|
1451
1676
|
const base = {
|
|
1452
1677
|
name: f['Nm '],
|
|
1453
1678
|
opacity: (0, descriptor_1.parsePercent)(f.blendOptions.Opct),
|
|
@@ -1495,7 +1720,7 @@ function parseFilterFXItem(f, options) {
|
|
|
1495
1720
|
undefinedAreas: descriptor_1.UndA.decode(f.Fltr.UndA),
|
|
1496
1721
|
displacementFile: {
|
|
1497
1722
|
signature: f.Fltr.DspF.sig,
|
|
1498
|
-
path: f.Fltr.DspF.path,
|
|
1723
|
+
path: f.Fltr.DspF.path,
|
|
1499
1724
|
},
|
|
1500
1725
|
} });
|
|
1501
1726
|
case 'Pnch': return Object.assign(Object.assign({}, base), { type: 'pinch', filter: {
|
|
@@ -1682,8 +1907,7 @@ function parseFilterFXItem(f, options) {
|
|
|
1682
1907
|
],
|
|
1683
1908
|
puppetShapeList: (f.Fltr.puppetShapeList || []).map(p => ({
|
|
1684
1909
|
rigidType: p.rigidType,
|
|
1685
|
-
//
|
|
1686
|
-
// TODO: VrsN
|
|
1910
|
+
// VrsM / VrsN - version (always 1.0)
|
|
1687
1911
|
originalVertexArray: uint8ToPoints(p.originalVertexArray),
|
|
1688
1912
|
deformedVertexArray: uint8ToPoints(p.deformedVertexArray),
|
|
1689
1913
|
indexArray: Array.from(uint8ToUint32(p.indexArray)),
|
|
@@ -1780,7 +2004,7 @@ function parseFilterFXItem(f, options) {
|
|
|
1780
2004
|
;
|
|
1781
2005
|
case 'Crvs':
|
|
1782
2006
|
{
|
|
1783
|
-
return Object.assign(Object.assign({}, base), { type: 'curves', filter: Object.assign({ presetKind: descriptor_1.presetKindType.decode(f.Fltr.presetKind) }, (f.Fltr.Adjs ? {
|
|
2007
|
+
return Object.assign(Object.assign({}, base), { type: 'curves', filter: Object.assign(Object.assign({}, (f.Fltr.presetKind !== undefined ? { presetKind: descriptor_1.presetKindType.decode(f.Fltr.presetKind) } : {})), (f.Fltr.Adjs ? {
|
|
1784
2008
|
adjustments: f.Fltr.Adjs.map(a => {
|
|
1785
2009
|
const channels = a.Chnl.map(descriptor_1.Chnl.decode);
|
|
1786
2010
|
if (a['Crv ']) {
|
|
@@ -1804,6 +2028,35 @@ function parseFilterFXItem(f, options) {
|
|
|
1804
2028
|
} : {})) });
|
|
1805
2029
|
}
|
|
1806
2030
|
;
|
|
2031
|
+
case 'Lvls':
|
|
2032
|
+
{
|
|
2033
|
+
const adjustments = f.Fltr.Adjs;
|
|
2034
|
+
const isKnown = (obj, keys) => Object.keys(obj).every(k => keys.indexOf(k) !== -1);
|
|
2035
|
+
// skip filter with settings we don't know about
|
|
2036
|
+
if (!isKnown(f.Fltr, levelsFilterKeys) || (adjustments && !adjustments.every(a => isKnown(a, levelsFilterAdjustmentKeys)))) {
|
|
2037
|
+
if (reader.throwForMissingFeatures)
|
|
2038
|
+
throw new Error('Unknown levels filter settings');
|
|
2039
|
+
reader.logMissingFeatures && reader.log(`Skipped levels smart filter with unknown settings`);
|
|
2040
|
+
return undefined;
|
|
2041
|
+
}
|
|
2042
|
+
return Object.assign(Object.assign({}, base), { type: 'levels', filter: Object.assign(Object.assign({}, (f.Fltr.presetKind !== undefined ? { presetKind: descriptor_1.presetKindType.decode(f.Fltr.presetKind) } : {})), (adjustments ? {
|
|
2043
|
+
adjustments: adjustments.map(a => {
|
|
2044
|
+
const result = { channels: a.Chnl.map(descriptor_1.Chnl.decode) };
|
|
2045
|
+
if (a.Inpt) {
|
|
2046
|
+
result.shadowInput = a.Inpt[0];
|
|
2047
|
+
result.highlightInput = a.Inpt[1];
|
|
2048
|
+
}
|
|
2049
|
+
if (a.Otpt) {
|
|
2050
|
+
result.shadowOutput = a.Otpt[0];
|
|
2051
|
+
result.highlightOutput = a.Otpt[1];
|
|
2052
|
+
}
|
|
2053
|
+
if (a['Gmm '] !== undefined)
|
|
2054
|
+
result.midtoneInput = a['Gmm '];
|
|
2055
|
+
return result;
|
|
2056
|
+
}),
|
|
2057
|
+
} : {})) });
|
|
2058
|
+
}
|
|
2059
|
+
;
|
|
1807
2060
|
case 'BrgC':
|
|
1808
2061
|
{
|
|
1809
2062
|
return Object.assign(Object.assign({}, base), { type: 'brightness/contrast', filter: {
|
|
@@ -1814,10 +2067,11 @@ function parseFilterFXItem(f, options) {
|
|
|
1814
2067
|
}
|
|
1815
2068
|
;
|
|
1816
2069
|
default:
|
|
1817
|
-
if (
|
|
2070
|
+
if (reader.throwForMissingFeatures) {
|
|
1818
2071
|
// console.log('FILTER', require('util').inspect(f, false, 99, true));
|
|
1819
2072
|
throw new Error(`Unknown filter classId: ${f.Fltr._classID}`);
|
|
1820
2073
|
}
|
|
2074
|
+
reader.logMissingFeatures && reader.log(`Unhandled smart filter: ${f.Fltr._classID} (${f['Nm ']})`);
|
|
1821
2075
|
return undefined;
|
|
1822
2076
|
}
|
|
1823
2077
|
}
|
|
@@ -1837,21 +2091,23 @@ function parseFilterFXItem(f, options) {
|
|
|
1837
2091
|
case 1314149187: return Object.assign(Object.assign({}, base), { type: 'ntsc colors' });
|
|
1838
2092
|
case 1231976050: return Object.assign(Object.assign({}, base), { type: 'invert' });
|
|
1839
2093
|
default:
|
|
1840
|
-
if (
|
|
2094
|
+
if (reader.throwForMissingFeatures) {
|
|
1841
2095
|
// console.log('FILTER', require('util').inspect(f, false, 99, true));
|
|
1842
2096
|
throw new Error(`Unknown filterID: ${f.filterID}`);
|
|
1843
2097
|
}
|
|
2098
|
+
reader.logMissingFeatures && reader.log(`Unhandled smart filter: ${f.filterID} (${f['Nm ']})`);
|
|
2099
|
+
return undefined;
|
|
1844
2100
|
}
|
|
1845
2101
|
}
|
|
1846
2102
|
}
|
|
1847
|
-
function parseFilterFX(desc,
|
|
2103
|
+
function parseFilterFX(desc, reader) {
|
|
1848
2104
|
return {
|
|
1849
2105
|
enabled: desc.enab,
|
|
1850
2106
|
validAtPosition: desc.validAtPosition,
|
|
1851
2107
|
maskEnabled: desc.filterMaskEnable,
|
|
1852
2108
|
maskLinked: desc.filterMaskLinked,
|
|
1853
2109
|
maskExtendWithWhite: desc.filterMaskExtendWithWhite,
|
|
1854
|
-
list: desc.filterFXList.map(x => parseFilterFXItem(x,
|
|
2110
|
+
list: desc.filterFXList.map(x => parseFilterFXItem(x, reader)).filter((x) => !!x),
|
|
1855
2111
|
};
|
|
1856
2112
|
}
|
|
1857
2113
|
function uvRadius(t) {
|
|
@@ -2207,14 +2463,14 @@ function serializeFilterFXItem(f) {
|
|
|
2207
2463
|
case 'puppet': return Object.assign(Object.assign({}, base), { Fltr: {
|
|
2208
2464
|
_name: 'Rigid Transform',
|
|
2209
2465
|
_classID: 'rigidTransform',
|
|
2210
|
-
'null': ['Ordn.Trgt'], //
|
|
2466
|
+
'null': ['Ordn.Trgt'], // target layer reference
|
|
2211
2467
|
rigidType: f.filter.rigidType,
|
|
2212
2468
|
puppetShapeList: (f.filter.puppetShapeList || []).map(p => ({
|
|
2213
2469
|
_name: '',
|
|
2214
2470
|
_classID: 'puppetShape',
|
|
2215
2471
|
rigidType: p.rigidType,
|
|
2216
|
-
VrsM: 1, //
|
|
2217
|
-
VrsN: 0, //
|
|
2472
|
+
VrsM: 1, // version major
|
|
2473
|
+
VrsN: 0, // version minor
|
|
2218
2474
|
originalVertexArray: toUint8(new Float32Array(pointsToArray(p.originalVertexArray))),
|
|
2219
2475
|
deformedVertexArray: toUint8(new Float32Array(pointsToArray(p.deformedVertexArray))),
|
|
2220
2476
|
indexArray: toUint8(new Uint32Array(p.indexArray)),
|
|
@@ -2296,7 +2552,7 @@ function serializeFilterFXItem(f) {
|
|
|
2296
2552
|
warpedVertices: f.filter.warpedVertices.map(pointToHrznVrtc),
|
|
2297
2553
|
quads: f.filter.quads.map(indices => ({ _name: '', _classID: 'quadIndices', indices })),
|
|
2298
2554
|
}, filterID: 442 });
|
|
2299
|
-
case 'curves': return Object.assign(Object.assign({}, base), { Fltr: Object.assign({ _name: 'Curves', _classID: 'Crvs', presetKind: descriptor_1.presetKindType.encode(f.filter.presetKind) }, (f.filter.adjustments ? {
|
|
2555
|
+
case 'curves': return Object.assign(Object.assign({}, base), { Fltr: Object.assign(Object.assign({ _name: 'Curves', _classID: 'Crvs' }, (f.filter.presetKind !== undefined ? { presetKind: descriptor_1.presetKindType.encode(f.filter.presetKind) } : {})), (f.filter.adjustments ? {
|
|
2300
2556
|
Adjs: f.filter.adjustments.map(a => 'curve' in a ? {
|
|
2301
2557
|
_name: '',
|
|
2302
2558
|
_classID: 'CrvA',
|
|
@@ -2309,6 +2565,21 @@ function serializeFilterFXItem(f) {
|
|
|
2309
2565
|
Mpng: a.values,
|
|
2310
2566
|
})
|
|
2311
2567
|
} : {})), filterID: 1131574899 });
|
|
2568
|
+
case 'levels': return Object.assign(Object.assign({}, base), { Fltr: Object.assign(Object.assign({ _name: 'Levels', _classID: 'Lvls' }, (f.filter.presetKind !== undefined ? { presetKind: descriptor_1.presetKindType.encode(f.filter.presetKind) } : {})), (f.filter.adjustments ? {
|
|
2569
|
+
Adjs: f.filter.adjustments.map(a => {
|
|
2570
|
+
var _a, _b, _c, _d;
|
|
2571
|
+
const adjustment = { _name: '', _classID: 'LvlA', Chnl: a.channels.map(descriptor_1.Chnl.encode) };
|
|
2572
|
+
if (a.shadowInput !== undefined || a.highlightInput !== undefined) {
|
|
2573
|
+
adjustment.Inpt = [Math.round((_a = a.shadowInput) !== null && _a !== void 0 ? _a : 0), Math.round((_b = a.highlightInput) !== null && _b !== void 0 ? _b : 255)];
|
|
2574
|
+
}
|
|
2575
|
+
if (a.shadowOutput !== undefined || a.highlightOutput !== undefined) {
|
|
2576
|
+
adjustment.Otpt = [Math.round((_c = a.shadowOutput) !== null && _c !== void 0 ? _c : 0), Math.round((_d = a.highlightOutput) !== null && _d !== void 0 ? _d : 255)];
|
|
2577
|
+
}
|
|
2578
|
+
if (a.midtoneInput !== undefined)
|
|
2579
|
+
adjustment['Gmm '] = a.midtoneInput;
|
|
2580
|
+
return adjustment;
|
|
2581
|
+
}),
|
|
2582
|
+
} : {})), filterID: 1282829427 });
|
|
2312
2583
|
case 'brightness/contrast': return Object.assign(Object.assign({}, base), { Fltr: {
|
|
2313
2584
|
_name: 'Brightness/Contrast',
|
|
2314
2585
|
_classID: 'BrgC',
|
|
@@ -2359,7 +2630,8 @@ function getWarpFromPlacedLayer(placed) {
|
|
|
2359
2630
|
},
|
|
2360
2631
|
};
|
|
2361
2632
|
}
|
|
2362
|
-
addHandler('SoLd',
|
|
2633
|
+
addHandler('SoLd', target => !!target.placedLayer && !target.placedLayer.external, // linked smart objects are stored in SoLE
|
|
2634
|
+
(reader, target, left) => {
|
|
2363
2635
|
if ((0, psdReader_1.readSignature)(reader) !== 'soLD')
|
|
2364
2636
|
throw new Error(`Invalid SoLd type`);
|
|
2365
2637
|
const version = (0, psdReader_1.readInt32)(reader);
|
|
@@ -2416,13 +2688,18 @@ addHandler('SoLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
2416
2688
|
const placedType = placedLayerTypes.indexOf(placed.type);
|
|
2417
2689
|
if (placedType === -1)
|
|
2418
2690
|
throw new Error('Invalid placedLayer type');
|
|
2691
|
+
const warp = getWarpFromPlacedLayer(placed);
|
|
2692
|
+
// size of linked image matches warp bounds if it's not provided
|
|
2693
|
+
const bounds = warp.bounds;
|
|
2694
|
+
const width = placed.width || (bounds ? bounds.right.value - bounds.left.value : 0);
|
|
2695
|
+
const height = placed.height || (bounds ? bounds.bottom.value - bounds.top.value : 0);
|
|
2419
2696
|
const desc = Object.assign(Object.assign({ Idnt: placed.id, placed: (_a = placed.placed) !== null && _a !== void 0 ? _a : placed.id, PgNm: placed.pageNumber || 1, totalPages: placed.totalPages || 1 }, (placed.crop ? { Crop: placed.crop } : {})), { frameStep: placed.frameStep || { numerator: 0, denominator: 600 }, duration: placed.duration || { numerator: 0, denominator: 600 }, frameCount: placed.frameCount || 0, Annt: 16, Type: placedType, Trnf: placed.transform, nonAffineTransform: (_b = placed.nonAffineTransform) !== null && _b !== void 0 ? _b : placed.transform,
|
|
2420
2697
|
// quiltWarp: {} as any,
|
|
2421
|
-
warp: encodeWarp(
|
|
2698
|
+
warp: encodeWarp(warp), 'Sz ': {
|
|
2422
2699
|
_name: '',
|
|
2423
2700
|
_classID: 'Pnt ',
|
|
2424
|
-
Wdth:
|
|
2425
|
-
Hght:
|
|
2701
|
+
Wdth: width,
|
|
2702
|
+
Hght: height,
|
|
2426
2703
|
}, Rslt: placed.resolution ? (0, descriptor_1.unitsValue)(placed.resolution, 'resolution') : { units: 'Density', value: 72 } });
|
|
2427
2704
|
if (placed.filter) {
|
|
2428
2705
|
desc.filterFX = {
|
|
@@ -2436,14 +2713,6 @@ addHandler('SoLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
2436
2713
|
filterFXList: placed.filter.list.map(f => serializeFilterFXItem(f)),
|
|
2437
2714
|
};
|
|
2438
2715
|
}
|
|
2439
|
-
// TODO:
|
|
2440
|
-
// desc.comp = -1;
|
|
2441
|
-
// desc.compInfo = { _name: '', _classID: 'null', compID: -1, originalCompID: -1 } as any;
|
|
2442
|
-
// desc.ClMg = {
|
|
2443
|
-
// _name: '',
|
|
2444
|
-
// _classID: 'ClMg',
|
|
2445
|
-
// placedLayerOCIOConversion: 'placedLayerOCIOConversion.placedLayerOCIOConvertEmbedded'
|
|
2446
|
-
// } as any;
|
|
2447
2716
|
// if (JSON.stringify(t) !== JSON.stringify(desc)) {
|
|
2448
2717
|
// console.log('read', require('util').inspect(t, false, 99, true));
|
|
2449
2718
|
// console.log('write', require('util').inspect(desc, false, 99, true));
|
|
@@ -2473,7 +2742,13 @@ addHandler('SoLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
2473
2742
|
desc.compInfo = placed.compInfo;
|
|
2474
2743
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc, desc.quiltWarp ? 'quiltWarp' : 'warp');
|
|
2475
2744
|
});
|
|
2476
|
-
|
|
2745
|
+
const soLdHandler = exports.infoHandlersMap['SoLd'];
|
|
2746
|
+
addHandler('SoLE', // linked smart object (Photoshop doesn't write PlLd for these)
|
|
2747
|
+
// linked smart object (Photoshop doesn't write PlLd for these)
|
|
2748
|
+
target => { var _a; return !!((_a = target.placedLayer) === null || _a === void 0 ? void 0 : _a.external); }, (reader, target, left, psd, imageResources) => {
|
|
2749
|
+
soLdHandler.read(reader, target, left, psd, imageResources);
|
|
2750
|
+
target.placedLayer.external = true;
|
|
2751
|
+
}, soLdHandler.write);
|
|
2477
2752
|
addHandler('fxrp', hasKey('referencePoint'), (reader, target) => {
|
|
2478
2753
|
target.referencePoint = {
|
|
2479
2754
|
x: (0, psdReader_1.readFloat64)(reader),
|
|
@@ -2483,14 +2758,37 @@ addHandler('fxrp', hasKey('referencePoint'), (reader, target) => {
|
|
|
2483
2758
|
(0, psdWriter_1.writeFloat64)(writer, target.referencePoint.x);
|
|
2484
2759
|
(0, psdWriter_1.writeFloat64)(writer, target.referencePoint.y);
|
|
2485
2760
|
});
|
|
2486
|
-
|
|
2487
|
-
(
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2761
|
+
function createGlobalLayerInfoHandler(key, bitsPerChannel) {
|
|
2762
|
+
addHandler(key, () => false, (reader, _target, left, psd, imageResources) => {
|
|
2763
|
+
var _a;
|
|
2764
|
+
// Photoshop writes empty (or 8bit compatibility) layer info section alongside Lr16/Lr32 in 16/32bit documents,
|
|
2765
|
+
// layers from global info with matching bit depth replace layers from that section, other ones are only used
|
|
2766
|
+
// if the section is empty
|
|
2767
|
+
if (!reader.layersInGlobalInfo && (psd.bitsPerChannel === bitsPerChannel || !((_a = psd.children) === null || _a === void 0 ? void 0 : _a.length))) {
|
|
2768
|
+
const sectionLayers = psd.children;
|
|
2769
|
+
psd.children = [];
|
|
2770
|
+
try {
|
|
2771
|
+
(0, psdReader_1.readLayerInfo)(reader, psd, imageResources);
|
|
2772
|
+
}
|
|
2773
|
+
catch (e) {
|
|
2774
|
+
psd.children = sectionLayers; // keep layers from layer info section if global info is broken
|
|
2775
|
+
throw e;
|
|
2776
|
+
}
|
|
2777
|
+
reader.layersInGlobalInfo = true;
|
|
2778
|
+
}
|
|
2779
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
2780
|
+
}, () => { });
|
|
2781
|
+
}
|
|
2782
|
+
createGlobalLayerInfoHandler('Lr16', 16);
|
|
2783
|
+
createGlobalLayerInfoHandler('Lr32', 32);
|
|
2784
|
+
createGlobalLayerInfoHandler('Layr', undefined);
|
|
2785
|
+
// merged transparency markers, first extra channel of composite image is transparency
|
|
2786
|
+
for (const key of ['Mtrn', 'Mt16', 'Mt32']) {
|
|
2787
|
+
addHandler(key, () => false, (reader, _target, left) => {
|
|
2788
|
+
reader.globalAlpha = true;
|
|
2789
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
2790
|
+
}, () => { });
|
|
2791
|
+
}
|
|
2494
2792
|
addHandler('LMsk', hasKey('userMask'), (reader, target) => {
|
|
2495
2793
|
target.userMask = {
|
|
2496
2794
|
colorSpace: (0, psdReader_1.readColor)(reader),
|
|
@@ -2514,11 +2812,13 @@ if (helpers_1.MOCK_HANDLERS) {
|
|
|
2514
2812
|
}, (writer, target) => false && (0, psdWriter_1.writeBytes)(writer, target._Patt));
|
|
2515
2813
|
}
|
|
2516
2814
|
else {
|
|
2517
|
-
addHandler('Patt', //
|
|
2518
|
-
//
|
|
2815
|
+
addHandler('Patt', // 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
|
|
2816
|
+
// 'Pat2' and 'Pat3' (16 and 32 bit documents) are aliases, patterns are always written as 8 bit
|
|
2519
2817
|
target => !!(target.patterns && target.patterns.length > 0), (reader, target, left) => {
|
|
2520
2818
|
while (left() > 0) {
|
|
2521
|
-
const pattern = (0, psdReader_1.
|
|
2819
|
+
const pattern = (0, psdReader_1.readPatternSafe)(reader);
|
|
2820
|
+
if (!pattern)
|
|
2821
|
+
continue;
|
|
2522
2822
|
if (target.patterns === undefined)
|
|
2523
2823
|
target.patterns = [];
|
|
2524
2824
|
target.patterns.push(pattern);
|
|
@@ -2706,6 +3006,10 @@ addHandler('Anno', target => target.annotations !== undefined, (reader, target,
|
|
|
2706
3006
|
writer.view.setUint32(dataOffset - 4, writer.offset - dataOffset, false);
|
|
2707
3007
|
}
|
|
2708
3008
|
});
|
|
3009
|
+
function readFileTypeSignature(reader) {
|
|
3010
|
+
const value = (0, psdReader_1.readSignature)(reader);
|
|
3011
|
+
return /^[\0 ]*$/.test(value) ? '' : value.trim(); // empty value is stored as spaces or zeros
|
|
3012
|
+
}
|
|
2709
3013
|
function createLnkHandler(tag) {
|
|
2710
3014
|
addHandler(tag, (target) => {
|
|
2711
3015
|
const psd = target;
|
|
@@ -2727,8 +3031,8 @@ function createLnkHandler(tag) {
|
|
|
2727
3031
|
const version = (0, psdReader_1.readInt32)(reader);
|
|
2728
3032
|
const id = (0, psdReader_1.readPascalString)(reader, 1);
|
|
2729
3033
|
const name = (0, psdReader_1.readUnicodeString)(reader);
|
|
2730
|
-
const fileType = (
|
|
2731
|
-
const fileCreator = (
|
|
3034
|
+
const fileType = readFileTypeSignature(reader); // ' ' if empty
|
|
3035
|
+
const fileCreator = readFileTypeSignature(reader); // ' ' or '\0\0\0\0' if empty
|
|
2732
3036
|
const dataSize = readLength64(reader);
|
|
2733
3037
|
const hasFileOpenDescriptor = (0, psdReader_1.readUint8)(reader);
|
|
2734
3038
|
const fileOpenDescriptor = hasFileOpenDescriptor ? (0, descriptor_1.readVersionAndDescriptor)(reader) : undefined;
|
|
@@ -2879,28 +3183,40 @@ createLnkHandler('lnk2');
|
|
|
2879
3183
|
createLnkHandler('lnkE');
|
|
2880
3184
|
addHandlerAlias('lnkD', 'lnk2');
|
|
2881
3185
|
addHandlerAlias('lnk3', 'lnk2');
|
|
2882
|
-
|
|
3186
|
+
// unicode names of saved paths (path data is stored in image resources 2000-2998)
|
|
3187
|
+
addHandler('pths', target => { var _a; return ((_a = target.imageResources) === null || _a === void 0 ? void 0 : _a.savedPaths) !== undefined; }, (reader, _target, left, psd) => {
|
|
3188
|
+
var _a, _b;
|
|
2883
3189
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
desc;
|
|
2887
|
-
|
|
2888
|
-
|
|
3190
|
+
const imageResources = (_a = psd.imageResources) !== null && _a !== void 0 ? _a : (psd.imageResources = {});
|
|
3191
|
+
const savedPaths = (_b = imageResources.savedPaths) !== null && _b !== void 0 ? _b : (imageResources.savedPaths = []);
|
|
3192
|
+
for (let i = 0; i < desc.pathList.length && i < savedPaths.length; i++) {
|
|
3193
|
+
const { pathUnicodeName, pathSymmetryClass } = desc.pathList[i];
|
|
3194
|
+
const path = savedPaths[i];
|
|
3195
|
+
// clipping path is referenced by (non-unicode) name
|
|
3196
|
+
if (imageResources.clippingPath && imageResources.clippingPath.name === path.name) {
|
|
3197
|
+
imageResources.clippingPath.name = pathUnicodeName;
|
|
3198
|
+
}
|
|
3199
|
+
path.name = pathUnicodeName;
|
|
3200
|
+
if (pathSymmetryClass)
|
|
3201
|
+
path.symmetryMode = pathSymmetryClass.pathSymmetryMode.split('.')[1];
|
|
3202
|
+
}
|
|
3203
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
3204
|
+
}, (writer, _target, psd) => {
|
|
2889
3205
|
const desc = {
|
|
2890
|
-
pathList:
|
|
3206
|
+
pathList: psd.imageResources.savedPaths.map(path => (Object.assign({ _name: '', _classID: 'pathInfoClass', pathUnicodeName: path.name }, (path.symmetryMode ? {
|
|
3207
|
+
pathSymmetryClass: {
|
|
3208
|
+
_name: '',
|
|
3209
|
+
_classID: 'pathSymmetryClass',
|
|
3210
|
+
pathSymmetryMode: `pathSymmetryModeEnum.${path.symmetryMode}`,
|
|
3211
|
+
},
|
|
3212
|
+
} : {})))),
|
|
2891
3213
|
};
|
|
2892
3214
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'pathsDataClass', desc);
|
|
2893
3215
|
});
|
|
2894
3216
|
addHandler('lyvr', hasKey('version'), (reader, target) => target.version = (0, psdReader_1.readUint32)(reader), (writer, target) => (0, psdWriter_1.writeUint32)(writer, target.version));
|
|
2895
|
-
addHandler('lfxs',
|
|
2896
|
-
//
|
|
2897
|
-
|
|
2898
|
-
// !!target.effects.dropShadow?.some(e => e.choke) ||
|
|
2899
|
-
// !!target.effects.innerShadow?.some(e => e.choke) ||
|
|
2900
|
-
// !!target.effects.outerGlow?.choke ||
|
|
2901
|
-
// !!target.effects.innerGlow?.choke
|
|
2902
|
-
// ),
|
|
2903
|
-
(reader, target, left) => {
|
|
3217
|
+
addHandler('lfxs', // effects of group layers (instead of 'lfx2' / 'lmfx')
|
|
3218
|
+
// effects of group layers (instead of 'lfx2' / 'lmfx')
|
|
3219
|
+
target => target.effects !== undefined && isGroupLayer(target), (reader, target, left) => {
|
|
2904
3220
|
const version = (0, psdReader_1.readUint32)(reader);
|
|
2905
3221
|
if (version !== 0)
|
|
2906
3222
|
throw new Error(`Invalid lfxs version`);
|
|
@@ -2944,6 +3260,10 @@ function readLevelsChannel(reader) {
|
|
|
2944
3260
|
const midtoneInput = (0, psdReader_1.readInt16)(reader) / 100;
|
|
2945
3261
|
return { shadowInput, highlightInput, shadowOutput, highlightOutput, midtoneInput };
|
|
2946
3262
|
}
|
|
3263
|
+
const defaultLevelsChannel = { shadowInput: 0, highlightInput: 255, shadowOutput: 0, highlightOutput: 255, midtoneInput: 1 };
|
|
3264
|
+
function isDefaultLevelsChannel(c) {
|
|
3265
|
+
return c.shadowInput === 0 && c.highlightInput === 255 && c.shadowOutput === 0 && c.highlightOutput === 255 && c.midtoneInput === 1;
|
|
3266
|
+
}
|
|
2947
3267
|
function writeLevelsChannel(writer, channel) {
|
|
2948
3268
|
(0, psdWriter_1.writeInt16)(writer, channel.shadowInput);
|
|
2949
3269
|
(0, psdWriter_1.writeInt16)(writer, channel.highlightInput);
|
|
@@ -2954,48 +3274,36 @@ function writeLevelsChannel(writer, channel) {
|
|
|
2954
3274
|
addHandler('levl', adjustmentType('levels'), (reader, target, left) => {
|
|
2955
3275
|
if ((0, psdReader_1.readUint16)(reader) !== 2)
|
|
2956
3276
|
throw new Error('Invalid levl version');
|
|
2957
|
-
const
|
|
2958
|
-
for (let i = 0; i < 29 && left(); i++) {
|
|
2959
|
-
|
|
2960
|
-
}
|
|
2961
|
-
|
|
2962
|
-
target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'levels', rgb,
|
|
2963
|
-
red,
|
|
2964
|
-
green,
|
|
2965
|
-
blue });
|
|
2966
|
-
if (left()) {
|
|
3277
|
+
const channels = [];
|
|
3278
|
+
for (let i = 0; i < 29 && left() >= 10; i++) {
|
|
3279
|
+
channels.push(readLevelsChannel(reader));
|
|
3280
|
+
}
|
|
3281
|
+
if (left() >= 8) {
|
|
2967
3282
|
if ((0, psdReader_1.readSignature)(reader) !== 'Lvls')
|
|
2968
3283
|
throw new Error(`Invalid levl signature`);
|
|
2969
3284
|
if ((0, psdReader_1.readUint16)(reader) !== 3)
|
|
2970
3285
|
throw new Error(`Invalid levl version`);
|
|
2971
3286
|
const totalChannelRecords = (0, psdReader_1.readUint16)(reader);
|
|
2972
|
-
|
|
2973
|
-
|
|
3287
|
+
while (channels.length < totalChannelRecords && left() >= 10) {
|
|
3288
|
+
channels.push(readLevelsChannel(reader));
|
|
2974
3289
|
}
|
|
2975
3290
|
}
|
|
3291
|
+
// records for all possible channels are stored, skip unused ones
|
|
3292
|
+
while (channels.length && isDefaultLevelsChannel(channels[channels.length - 1]))
|
|
3293
|
+
channels.pop();
|
|
3294
|
+
target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'levels', channels });
|
|
2976
3295
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
2977
3296
|
}, (writer, target) => {
|
|
2978
|
-
const
|
|
2979
|
-
const defaultChannel = {
|
|
2980
|
-
shadowInput: 0,
|
|
2981
|
-
highlightInput: 255,
|
|
2982
|
-
shadowOutput: 0,
|
|
2983
|
-
highlightOutput: 255,
|
|
2984
|
-
midtoneInput: 1,
|
|
2985
|
-
};
|
|
3297
|
+
const channels = target.adjustment.channels || [];
|
|
2986
3298
|
(0, psdWriter_1.writeUint16)(writer, 2); // version
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
writeLevelsChannel(writer, info.green || defaultChannel);
|
|
2990
|
-
writeLevelsChannel(writer, info.blue || defaultChannel);
|
|
2991
|
-
for (let i = 0; i < (29 - 4); i++) {
|
|
2992
|
-
writeLevelsChannel(writer, defaultChannel);
|
|
3299
|
+
for (let i = 0; i < 29; i++) {
|
|
3300
|
+
writeLevelsChannel(writer, channels[i] || defaultLevelsChannel);
|
|
2993
3301
|
}
|
|
2994
3302
|
(0, psdWriter_1.writeSignature)(writer, 'Lvls');
|
|
2995
3303
|
(0, psdWriter_1.writeUint16)(writer, 3); // version
|
|
2996
3304
|
(0, psdWriter_1.writeUint16)(writer, 62); // total count
|
|
2997
|
-
for (let i =
|
|
2998
|
-
writeLevelsChannel(writer,
|
|
3305
|
+
for (let i = 29; i < 62; i++) {
|
|
3306
|
+
writeLevelsChannel(writer, channels[i] || defaultLevelsChannel);
|
|
2999
3307
|
}
|
|
3000
3308
|
});
|
|
3001
3309
|
function readCurveChannel(reader) {
|
|
@@ -3020,17 +3328,16 @@ addHandler('curv', adjustmentType('curves'), (reader, target, left) => {
|
|
|
3020
3328
|
if ((0, psdReader_1.readUint16)(reader) !== 1)
|
|
3021
3329
|
throw new Error('Invalid curv version');
|
|
3022
3330
|
(0, psdReader_1.readUint16)(reader);
|
|
3023
|
-
const
|
|
3024
|
-
const
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
target.adjustment = Object.assign(Object.assign({}, target.adjustment), info);
|
|
3331
|
+
const channelsMask = (0, psdReader_1.readUint16)(reader);
|
|
3332
|
+
const channels = [];
|
|
3333
|
+
for (let i = 0; i < 16; i++) {
|
|
3334
|
+
if (channelsMask & (1 << i)) {
|
|
3335
|
+
while (channels.length < i)
|
|
3336
|
+
channels.push([]);
|
|
3337
|
+
channels.push(readCurveChannel(reader));
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'curves', channels });
|
|
3034
3341
|
// ignoring, duplicate information
|
|
3035
3342
|
// checkSignature(reader, 'Crv ');
|
|
3036
3343
|
// const cVersion = readUint16(reader);
|
|
@@ -3046,57 +3353,29 @@ addHandler('curv', adjustmentType('curves'), (reader, target, left) => {
|
|
|
3046
3353
|
// }
|
|
3047
3354
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
3048
3355
|
}, (writer, target) => {
|
|
3049
|
-
|
|
3050
|
-
const
|
|
3051
|
-
|
|
3052
|
-
let
|
|
3053
|
-
|
|
3054
|
-
channels
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
channels |= 2;
|
|
3059
|
-
channelCount++;
|
|
3060
|
-
}
|
|
3061
|
-
if (green && green.length) {
|
|
3062
|
-
channels |= 4;
|
|
3063
|
-
channelCount++;
|
|
3064
|
-
}
|
|
3065
|
-
if (blue && blue.length) {
|
|
3066
|
-
channels |= 8;
|
|
3067
|
-
channelCount++;
|
|
3356
|
+
var _a;
|
|
3357
|
+
const channels = (target.adjustment.channels || []).slice(0, 16);
|
|
3358
|
+
const used = [];
|
|
3359
|
+
let channelsMask = 0;
|
|
3360
|
+
for (let i = 0; i < channels.length; i++) {
|
|
3361
|
+
if ((_a = channels[i]) === null || _a === void 0 ? void 0 : _a.length) {
|
|
3362
|
+
channelsMask |= 1 << i;
|
|
3363
|
+
used.push(i);
|
|
3364
|
+
}
|
|
3068
3365
|
}
|
|
3069
3366
|
(0, psdWriter_1.writeUint8)(writer, 0);
|
|
3070
3367
|
(0, psdWriter_1.writeUint16)(writer, 1); // version
|
|
3071
3368
|
(0, psdWriter_1.writeUint16)(writer, 0);
|
|
3072
|
-
(0, psdWriter_1.writeUint16)(writer,
|
|
3073
|
-
|
|
3074
|
-
writeCurveChannel(writer,
|
|
3075
|
-
if (red && red.length)
|
|
3076
|
-
writeCurveChannel(writer, red);
|
|
3077
|
-
if (green && green.length)
|
|
3078
|
-
writeCurveChannel(writer, green);
|
|
3079
|
-
if (blue && blue.length)
|
|
3080
|
-
writeCurveChannel(writer, blue);
|
|
3369
|
+
(0, psdWriter_1.writeUint16)(writer, channelsMask);
|
|
3370
|
+
for (const i of used)
|
|
3371
|
+
writeCurveChannel(writer, channels[i]);
|
|
3081
3372
|
(0, psdWriter_1.writeSignature)(writer, 'Crv ');
|
|
3082
3373
|
(0, psdWriter_1.writeUint16)(writer, 4); // version
|
|
3083
3374
|
(0, psdWriter_1.writeUint16)(writer, 0);
|
|
3084
|
-
(0, psdWriter_1.writeUint16)(writer,
|
|
3085
|
-
|
|
3086
|
-
(0, psdWriter_1.writeUint16)(writer,
|
|
3087
|
-
writeCurveChannel(writer,
|
|
3088
|
-
}
|
|
3089
|
-
if (red && red.length) {
|
|
3090
|
-
(0, psdWriter_1.writeUint16)(writer, 1);
|
|
3091
|
-
writeCurveChannel(writer, red);
|
|
3092
|
-
}
|
|
3093
|
-
if (green && green.length) {
|
|
3094
|
-
(0, psdWriter_1.writeUint16)(writer, 2);
|
|
3095
|
-
writeCurveChannel(writer, green);
|
|
3096
|
-
}
|
|
3097
|
-
if (blue && blue.length) {
|
|
3098
|
-
(0, psdWriter_1.writeUint16)(writer, 3);
|
|
3099
|
-
writeCurveChannel(writer, blue);
|
|
3375
|
+
(0, psdWriter_1.writeUint16)(writer, used.length);
|
|
3376
|
+
for (const i of used) {
|
|
3377
|
+
(0, psdWriter_1.writeUint16)(writer, i);
|
|
3378
|
+
writeCurveChannel(writer, channels[i]);
|
|
3100
3379
|
}
|
|
3101
3380
|
});
|
|
3102
3381
|
addHandler('expA', adjustmentType('exposure'), (reader, target, left) => {
|
|
@@ -3153,12 +3432,34 @@ function writeHueChannel(writer, channel) {
|
|
|
3153
3432
|
addHandler('hue2', adjustmentType('hue/saturation'), (reader, target, left) => {
|
|
3154
3433
|
if ((0, psdReader_1.readUint16)(reader) !== 2)
|
|
3155
3434
|
throw new Error('Invalid hue2 version');
|
|
3156
|
-
|
|
3435
|
+
const colorize = !!(0, psdReader_1.readUint8)(reader);
|
|
3436
|
+
(0, psdReader_1.skipBytes)(reader, 1);
|
|
3437
|
+
const colorizeHue = (0, psdReader_1.readInt16)(reader); // stored as -180..180
|
|
3438
|
+
const colorizeSaturation = (0, psdReader_1.readInt16)(reader);
|
|
3439
|
+
const colorizeLightness = (0, psdReader_1.readInt16)(reader);
|
|
3440
|
+
target.adjustment = Object.assign(Object.assign({}, target.adjustment), { type: 'hue/saturation', colorize, colorization: {
|
|
3441
|
+
hue: colorizeHue < 0 ? colorizeHue + 360 : colorizeHue,
|
|
3442
|
+
saturation: colorizeSaturation,
|
|
3443
|
+
lightness: colorizeLightness,
|
|
3444
|
+
}, master: {
|
|
3445
|
+
hue: (0, psdReader_1.readInt16)(reader),
|
|
3446
|
+
saturation: (0, psdReader_1.readInt16)(reader),
|
|
3447
|
+
lightness: (0, psdReader_1.readInt16)(reader),
|
|
3448
|
+
}, reds: readHueChannel(reader), yellows: readHueChannel(reader), greens: readHueChannel(reader), cyans: readHueChannel(reader), blues: readHueChannel(reader), magentas: readHueChannel(reader) });
|
|
3157
3449
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
3158
3450
|
}, (writer, target) => {
|
|
3451
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
3159
3452
|
const info = target.adjustment;
|
|
3160
3453
|
(0, psdWriter_1.writeUint16)(writer, 2); // version
|
|
3161
|
-
|
|
3454
|
+
(0, psdWriter_1.writeUint8)(writer, info.colorize ? 1 : 0);
|
|
3455
|
+
(0, psdWriter_1.writeUint8)(writer, 0);
|
|
3456
|
+
const colorizeHue = Math.round((_b = (_a = info.colorization) === null || _a === void 0 ? void 0 : _a.hue) !== null && _b !== void 0 ? _b : 0);
|
|
3457
|
+
(0, psdWriter_1.writeInt16)(writer, colorizeHue > 180 ? colorizeHue - 360 : colorizeHue);
|
|
3458
|
+
(0, psdWriter_1.writeInt16)(writer, Math.round((_d = (_c = info.colorization) === null || _c === void 0 ? void 0 : _c.saturation) !== null && _d !== void 0 ? _d : 0));
|
|
3459
|
+
(0, psdWriter_1.writeInt16)(writer, Math.round((_f = (_e = info.colorization) === null || _e === void 0 ? void 0 : _e.lightness) !== null && _f !== void 0 ? _f : 0));
|
|
3460
|
+
(0, psdWriter_1.writeInt16)(writer, Math.round((_h = (_g = info.master) === null || _g === void 0 ? void 0 : _g.hue) !== null && _h !== void 0 ? _h : 0));
|
|
3461
|
+
(0, psdWriter_1.writeInt16)(writer, Math.round((_k = (_j = info.master) === null || _j === void 0 ? void 0 : _j.saturation) !== null && _k !== void 0 ? _k : 0));
|
|
3462
|
+
(0, psdWriter_1.writeInt16)(writer, Math.round((_m = (_l = info.master) === null || _l === void 0 ? void 0 : _l.lightness) !== null && _m !== void 0 ? _m : 0));
|
|
3162
3463
|
writeHueChannel(writer, info.reds);
|
|
3163
3464
|
writeHueChannel(writer, info.yellows);
|
|
3164
3465
|
writeHueChannel(writer, info.greens);
|
|
@@ -3237,16 +3538,18 @@ addHandler('phfl', adjustmentType('photo filter'), (reader, target, left) => {
|
|
|
3237
3538
|
color = (0, psdReader_1.readColor)(reader);
|
|
3238
3539
|
}
|
|
3239
3540
|
else { // version 3
|
|
3240
|
-
//
|
|
3241
|
-
//
|
|
3242
|
-
|
|
3243
|
-
const
|
|
3244
|
-
const
|
|
3245
|
-
|
|
3541
|
+
// XYZ color relative to D50 white point, 32768 = 1.0 (not documented, matches colors of Photoshop presets),
|
|
3542
|
+
// converted to Lab (same scale as readColor()) so it can be written back as version 2
|
|
3543
|
+
const x = (0, psdReader_1.readInt32)(reader) / 32768;
|
|
3544
|
+
const y = (0, psdReader_1.readInt32)(reader) / 32768;
|
|
3545
|
+
const z = (0, psdReader_1.readInt32)(reader) / 32768;
|
|
3546
|
+
if (!(x >= 0 && y >= 0 && z >= 0 && x <= 2 && y <= 2 && z <= 2))
|
|
3547
|
+
throw new Error('Invalid phfl XYZ color');
|
|
3548
|
+
const f = (t) => t > 216 / 24389 ? Math.cbrt(t) : (24389 / 27 * t + 16) / 116;
|
|
3246
3549
|
color = {
|
|
3247
|
-
l:
|
|
3248
|
-
a: (0, helpers_1.normalizeLabAB)(
|
|
3249
|
-
b: (0, helpers_1.normalizeLabAB)(
|
|
3550
|
+
l: Math.max(0, 116 * f(y) - 16) / 100,
|
|
3551
|
+
a: (0, helpers_1.normalizeLabAB)(500 * (f(x) - f(y))),
|
|
3552
|
+
b: (0, helpers_1.normalizeLabAB)(200 * (f(y) - f(z))),
|
|
3250
3553
|
};
|
|
3251
3554
|
}
|
|
3252
3555
|
target.adjustment = {
|
|
@@ -3414,7 +3717,7 @@ addHandler('grdm', adjustmentType('gradient map'), (reader, target, left) => {
|
|
|
3414
3717
|
reader.offset--;
|
|
3415
3718
|
if (hasMethod) {
|
|
3416
3719
|
const method = (0, psdReader_1.readSignature)(reader);
|
|
3417
|
-
info.method = descriptor_1.gradientInterpolationMethodType.decode(method);
|
|
3720
|
+
info.method = descriptor_1.gradientInterpolationMethodType.decode(`gradientInterpolationMethodType.${method}`);
|
|
3418
3721
|
}
|
|
3419
3722
|
info.name = (0, psdReader_1.readUnicodeString)(reader);
|
|
3420
3723
|
info.colorStops = [];
|
|
@@ -3476,7 +3779,7 @@ addHandler('grdm', adjustmentType('gradient map'), (reader, target, left) => {
|
|
|
3476
3779
|
(0, psdWriter_1.writeUint8)(writer, info.reverse ? 1 : 0);
|
|
3477
3780
|
(0, psdWriter_1.writeUint8)(writer, info.dither ? 1 : 0);
|
|
3478
3781
|
if (info.method !== undefined) {
|
|
3479
|
-
(0, psdWriter_1.writeSignature)(writer, descriptor_1.gradientInterpolationMethodType.encode(info.method));
|
|
3782
|
+
(0, psdWriter_1.writeSignature)(writer, descriptor_1.gradientInterpolationMethodType.encode(info.method).split('.')[1]);
|
|
3480
3783
|
}
|
|
3481
3784
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, info.name || '');
|
|
3482
3785
|
(0, psdWriter_1.writeUint16)(writer, info.colorStops && info.colorStops.length || 0);
|
|
@@ -3798,17 +4101,22 @@ addHandler('artd', // document-wide artboard info
|
|
|
3798
4101
|
// document-wide artboard info
|
|
3799
4102
|
target => target.artboards !== undefined, (reader, target, left) => {
|
|
3800
4103
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
3801
|
-
target.artboards = {
|
|
3802
|
-
|
|
3803
|
-
autoExpandOffset
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4104
|
+
const artboards = target.artboards = { count: desc['Cnt '] };
|
|
4105
|
+
if (desc.autoExpandOffset)
|
|
4106
|
+
artboards.autoExpandOffset = { horizontal: desc.autoExpandOffset.Hrzn, vertical: desc.autoExpandOffset.Vrtc };
|
|
4107
|
+
if (desc.origin)
|
|
4108
|
+
artboards.origin = { horizontal: desc.origin.Hrzn, vertical: desc.origin.Vrtc };
|
|
4109
|
+
if (desc.autoExpandEnabled !== undefined)
|
|
4110
|
+
artboards.autoExpandEnabled = desc.autoExpandEnabled;
|
|
4111
|
+
if (desc.autoNestEnabled !== undefined)
|
|
4112
|
+
artboards.autoNestEnabled = desc.autoNestEnabled;
|
|
4113
|
+
if (desc.autoPositionEnabled !== undefined)
|
|
4114
|
+
artboards.autoPositionEnabled = desc.autoPositionEnabled;
|
|
4115
|
+
artboards.shrinkwrapOnSaveEnabled = !!desc.shrinkwrapOnSaveEnabled;
|
|
4116
|
+
if (desc.docDefaultNewArtboardBackgroundColor)
|
|
4117
|
+
artboards.docDefaultNewArtboardBackgroundColor = (0, descriptor_1.parseColor)(desc.docDefaultNewArtboardBackgroundColor);
|
|
4118
|
+
if (desc.docDefaultNewArtboardBackgroundType !== undefined)
|
|
4119
|
+
artboards.docDefaultNewArtboardBackgroundType = desc.docDefaultNewArtboardBackgroundType;
|
|
3812
4120
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
3813
4121
|
}, (writer, target) => {
|
|
3814
4122
|
var _a, _b, _c, _d, _e;
|
|
@@ -3826,17 +4134,19 @@ target => target.artboards !== undefined, (reader, target, left) => {
|
|
|
3826
4134
|
};
|
|
3827
4135
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc, 'artd');
|
|
3828
4136
|
});
|
|
4137
|
+
function isGroupLayer(target) {
|
|
4138
|
+
return !!target.children;
|
|
4139
|
+
}
|
|
3829
4140
|
function hasMultiEffects(effects) {
|
|
3830
4141
|
return Object.keys(effects).map(key => effects[key]).some(v => Array.isArray(v) && v.length > 1);
|
|
3831
4142
|
}
|
|
3832
|
-
addHandler('lfx2', target => target.effects !== undefined && !hasMultiEffects(target.effects), (reader, target, left) => {
|
|
4143
|
+
addHandler('lfx2', target => target.effects !== undefined && !isGroupLayer(target) && !hasMultiEffects(target.effects), (reader, target, left) => {
|
|
3833
4144
|
const version = (0, psdReader_1.readUint32)(reader);
|
|
3834
4145
|
if (version !== 0)
|
|
3835
4146
|
throw new Error(`Invalid lfx2 version`);
|
|
3836
4147
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
3837
4148
|
// console.log('READ', require('util').inspect(desc, false, 99, true));
|
|
3838
|
-
//
|
|
3839
|
-
// discard if read in 'lrFX' section
|
|
4149
|
+
// discard if read in 'lrFX' section ('lmfx' and 'lfx2' are never stored together)
|
|
3840
4150
|
target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
|
|
3841
4151
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
3842
4152
|
}, (writer, target, _, options) => {
|
|
@@ -3893,16 +4203,14 @@ addHandler('cinf', hasKey('compositorUsed'), (reader, target, left) => {
|
|
|
3893
4203
|
desc.compCoreGPUSupport = `reason.${cinf.compCoreGPUSupport}`;
|
|
3894
4204
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
3895
4205
|
});
|
|
3896
|
-
//
|
|
3897
|
-
addHandler('extn', target => target.
|
|
4206
|
+
// generator settings of the document (layers store them in 'shmd' section)
|
|
4207
|
+
addHandler('extn', target => target.generatorSettings !== undefined && isDocument(target), (reader, target, left) => {
|
|
3898
4208
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
4209
|
+
if (desc.generatorSettings)
|
|
4210
|
+
target.generatorSettings = parseGeneratorSettings(desc.generatorSettings);
|
|
4211
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
3902
4212
|
}, (writer, target) => {
|
|
3903
|
-
|
|
3904
|
-
if (helpers_1.MOCK_HANDLERS)
|
|
3905
|
-
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', target._extn);
|
|
4213
|
+
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', serializeGeneratorSettings(target.generatorSettings));
|
|
3906
4214
|
});
|
|
3907
4215
|
addHandler('iOpa', hasKey('fillOpacity'), (reader, target) => {
|
|
3908
4216
|
target.fillOpacity = (0, psdReader_1.readUint8)(reader) / 0xff;
|
|
@@ -3980,14 +4288,13 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
3980
4288
|
return t;
|
|
3981
4289
|
};
|
|
3982
4290
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3983
|
-
exports.
|
|
3984
|
-
exports.presetKindType = exports.prjM = exports.FlMd = void 0;
|
|
4291
|
+
exports.Drct = exports.WndM = exports.CntE = exports.FlCl = exports.ExtR = exports.ExtT = exports.DfsM = exports.blurType = exports.Lns = exports.MztT = exports.Chnl = exports.Dstr = exports.ZZTy = exports.Wvtp = exports.SphM = exports.RplS = exports.Cnvr = exports.UndA = exports.DspM = exports.SmBQ = exports.SmBM = exports.BlrQ = exports.BlrM = exports.strokeStyleLineAlignment = exports.strokeStyleLineJoinType = exports.strokeStyleLineCapType = exports.ESliceBGColorType = exports.ESliceOrigin = exports.ESliceVertAlign = exports.ESliceHorzAlign = exports.ESliceType = exports.FrFl = exports.FStl = exports.ClrS = exports.Clry = exports.gradientInterpolationMethodType = exports.stdTrackID = exports.animInterpStyleEnum = exports.GrdT = exports.IGSr = exports.BETE = exports.BESs = exports.bvlT = exports.BESl = exports.BlnM = exports.warpStyle = exports.Annt = exports.Ornt = exports.textGridding = exports.outputSettingsRoot = void 0;
|
|
4292
|
+
exports.presetKindType = exports.prjM = exports.FlMd = exports.IntC = exports.IntE = void 0;
|
|
3985
4293
|
exports.setLogErrors = setLogErrors;
|
|
3986
4294
|
exports.readAsciiStringOrClassId = readAsciiStringOrClassId;
|
|
3987
4295
|
exports.writeAsciiStringOrClassId = writeAsciiStringOrClassId;
|
|
3988
4296
|
exports.readDescriptorStructure = readDescriptorStructure;
|
|
3989
4297
|
exports.writeDescriptorStructure = writeDescriptorStructure;
|
|
3990
|
-
exports.createDescriptorReference = createDescriptorReference;
|
|
3991
4298
|
exports.pathSelectionStateToReference = pathSelectionStateToReference;
|
|
3992
4299
|
exports.writeClassStructure = writeClassStructure;
|
|
3993
4300
|
exports.readVersionAndDescriptor = readVersionAndDescriptor;
|
|
@@ -4136,6 +4443,7 @@ const fieldToArrayExtType = {
|
|
|
4136
4443
|
Clrs: makeType('', 'Clrt'),
|
|
4137
4444
|
Trns: makeType('', 'TrnS'),
|
|
4138
4445
|
keyDescriptorList: nullType,
|
|
4446
|
+
keyRootDescriptorList: nullType,
|
|
4139
4447
|
solidFillMulti: makeType('', 'SoFi'),
|
|
4140
4448
|
gradientFillMulti: makeType('', 'GrFl'),
|
|
4141
4449
|
dropShadowMulti: makeType('', 'DrSh'),
|
|
@@ -4169,17 +4477,23 @@ const fieldToArrayExtType = {
|
|
|
4169
4477
|
};
|
|
4170
4478
|
const typeToField = {
|
|
4171
4479
|
'TEXT': [
|
|
4172
|
-
'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
|
|
4480
|
+
'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName', 'exportOption', 'scaleSettings',
|
|
4481
|
+
'BackgroundImagePath', 'ImageSubfolderName',
|
|
4173
4482
|
'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
|
|
4174
4483
|
'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
|
|
4175
|
-
'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath',
|
|
4484
|
+
'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath', 'Bk ', 'pathUnicodeName',
|
|
4176
4485
|
],
|
|
4177
4486
|
'tdta': [
|
|
4178
4487
|
'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
|
|
4179
|
-
'LqMe',
|
|
4488
|
+
'LqMe', 'bookKey',
|
|
4180
4489
|
],
|
|
4181
4490
|
'long': [
|
|
4182
|
-
'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
|
|
4491
|
+
'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ', 'bookID',
|
|
4492
|
+
'cropRectBottom', 'cropRectLeft', 'cropRectRight', 'cropRectTop',
|
|
4493
|
+
// save for web output settings
|
|
4494
|
+
'Version', 'BackgroundColorBlue', 'BackgroundColorGreen', 'BackgroundColorRed', 'BackgroundColorState', 'AttributeCase', 'Encoding',
|
|
4495
|
+
'DuplicateFileNameBehavior', 'ImageMapLocation', 'ImageMapType', 'Indent', 'LineEndings', 'SpacersEmptyCells',
|
|
4496
|
+
'SpacersHorizontal', 'SpacersVertical', 'StylesFormat', 'TDWidthHeight', 'TagCase', 'ColorPolicy', 'MetadataPolicy',
|
|
4183
4497
|
'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'comp', 'compID', 'originalCompID',
|
|
4184
4498
|
'curvesPresetKind', 'mixerPresetKind', 'uOrder', 'vOrder', 'PgNm', 'totalPages', 'Crop',
|
|
4185
4499
|
'numerator', 'denominator', 'frameCount', 'Annt', 'keyOriginType', 'unitValueQuadVersion',
|
|
@@ -4201,7 +4515,7 @@ const typeToField = {
|
|
|
4201
4515
|
'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
|
|
4202
4516
|
'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
|
|
4203
4517
|
'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
|
|
4204
|
-
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
|
|
4518
|
+
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod', 'pathSymmetryMode',
|
|
4205
4519
|
'interpretAlpha',
|
|
4206
4520
|
],
|
|
4207
4521
|
'bool': [
|
|
@@ -4218,7 +4532,7 @@ const typeToField = {
|
|
|
4218
4532
|
'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn',
|
|
4219
4533
|
],
|
|
4220
4534
|
'doub': [
|
|
4221
|
-
'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
|
|
4535
|
+
'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght', 'Gmm ',
|
|
4222
4536
|
'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
|
|
4223
4537
|
'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
|
|
4224
4538
|
'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
|
|
@@ -4232,7 +4546,7 @@ const typeToField = {
|
|
|
4232
4546
|
'topRight', 'topLeft', 'bottomLeft', 'bottomRight', 'ClNs', 'Shrp',
|
|
4233
4547
|
],
|
|
4234
4548
|
'VlLs': [
|
|
4235
|
-
'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
|
|
4549
|
+
'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'keyRootDescriptorList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
|
|
4236
4550
|
'LaSt', 'Trnf', 'nonAffineTransform', 'keyDescriptorList', 'guideIndeces', 'gradientFillMulti',
|
|
4237
4551
|
'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
|
|
4238
4552
|
'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
|
|
@@ -4251,25 +4565,6 @@ const channels = [
|
|
|
4251
4565
|
];
|
|
4252
4566
|
// color classes whose channel values are written as doubles ('GRYC' and 'LABC' are kept for backwards compatibility)
|
|
4253
4567
|
const doubleColorClasses = ['Grsc', 'LbCl', 'GRYC', 'LABC'];
|
|
4254
|
-
// Hidden (non-enumerable) markers used to remember how values were stored in the file, so they can be
|
|
4255
|
-
// written back the same way. They don't change the shape of the objects returned by the reader.
|
|
4256
|
-
const osTypeKey = typeof Symbol !== 'undefined' ? Symbol('agPsdOSType') : '__agPsdOSType';
|
|
4257
|
-
const obArInfoKey = typeof Symbol !== 'undefined' ? Symbol('agPsdObAr') : '__agPsdObAr';
|
|
4258
|
-
const referenceInfoKey = typeof Symbol !== 'undefined' ? Symbol('agPsdReference') : '__agPsdReference';
|
|
4259
|
-
function setHidden(target, key, value) {
|
|
4260
|
-
Object.defineProperty(target, key, { value, enumerable: false, configurable: true, writable: true });
|
|
4261
|
-
return target;
|
|
4262
|
-
}
|
|
4263
|
-
function getHidden(target, key) {
|
|
4264
|
-
return (target && typeof target === 'object') ? target[key] : undefined;
|
|
4265
|
-
}
|
|
4266
|
-
const osTypeFamilies = {
|
|
4267
|
-
UntF: 'UntF', UnFl: 'UntF',
|
|
4268
|
-
Objc: 'Objc', GlbO: 'Objc',
|
|
4269
|
-
type: 'type', GlbC: 'type',
|
|
4270
|
-
comp: 'comp',
|
|
4271
|
-
};
|
|
4272
|
-
// returns the OS type the value was originally read with, if it's compatible with the type we'd write it as
|
|
4273
4568
|
// fallback for unknown keys, based on the type of the value
|
|
4274
4569
|
function guessOSType(value) {
|
|
4275
4570
|
if (typeof value === 'boolean')
|
|
@@ -4278,26 +4573,33 @@ function guessOSType(value) {
|
|
|
4278
4573
|
return 'doub';
|
|
4279
4574
|
if (Array.isArray(value))
|
|
4280
4575
|
return 'VlLs';
|
|
4281
|
-
if (value && typeof value === 'object'
|
|
4282
|
-
|
|
4576
|
+
if (value && typeof value === 'object') {
|
|
4577
|
+
if (typeof value._classID === 'string')
|
|
4578
|
+
return 'Objc';
|
|
4579
|
+
if (typeof value.classID === 'string')
|
|
4580
|
+
return 'type'; // class read from 'type' or 'GlbC'
|
|
4581
|
+
if (typeof value.low === 'number' && typeof value.high === 'number')
|
|
4582
|
+
return 'comp';
|
|
4583
|
+
if (typeof value.units === 'string' && typeof value.value === 'number')
|
|
4584
|
+
return 'UntF';
|
|
4585
|
+
}
|
|
4283
4586
|
return undefined;
|
|
4284
4587
|
}
|
|
4285
|
-
function getRecordedOSType(value, type) {
|
|
4286
|
-
const recorded = getHidden(value, osTypeKey);
|
|
4287
|
-
if (!recorded)
|
|
4288
|
-
return type;
|
|
4289
|
-
if (!type || recorded === 'comp' || recorded === 'type' || recorded === 'GlbC')
|
|
4290
|
-
return recorded;
|
|
4291
|
-
return osTypeFamilies[recorded] === osTypeFamilies[type] ? recorded : type;
|
|
4292
|
-
}
|
|
4293
4588
|
const fieldToArrayType = {
|
|
4294
4589
|
'Mnm ': 'long',
|
|
4295
4590
|
'Mxm ': 'long',
|
|
4591
|
+
HtmlFileNameComponents: 'long', // save for web output settings
|
|
4592
|
+
SavingFileNameComponents: 'long',
|
|
4593
|
+
SliceFileNameComponents: 'long',
|
|
4594
|
+
Inpt: 'long', // levels filter
|
|
4595
|
+
Otpt: 'long', // levels filter
|
|
4296
4596
|
FrLs: 'long',
|
|
4297
4597
|
strokeStyleLineDashSet: 'UntF',
|
|
4298
4598
|
Trnf: 'doub',
|
|
4299
4599
|
nonAffineTransform: 'doub',
|
|
4300
4600
|
keyDescriptorList: 'Objc',
|
|
4601
|
+
keyRootDescriptorList: 'Objc',
|
|
4602
|
+
pathList: 'Objc',
|
|
4301
4603
|
gradientFillMulti: 'Objc',
|
|
4302
4604
|
solidFillMulti: 'Objc',
|
|
4303
4605
|
frameFXMulti: 'Objc',
|
|
@@ -4388,6 +4690,15 @@ function getTypeByKey(key, value, root, parent) {
|
|
|
4388
4690
|
else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'HsbP') {
|
|
4389
4691
|
return 'enum';
|
|
4390
4692
|
}
|
|
4693
|
+
else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'LvlA') {
|
|
4694
|
+
return 'VlLs';
|
|
4695
|
+
}
|
|
4696
|
+
else if (key === 'Intr' && typeof value === 'boolean') {
|
|
4697
|
+
return 'bool'; // interpolation in print style
|
|
4698
|
+
}
|
|
4699
|
+
else if (key === 'PgPs') {
|
|
4700
|
+
return 'enum';
|
|
4701
|
+
}
|
|
4391
4702
|
else if (key === 'LghD' && parent._classID === 'oilPaint') {
|
|
4392
4703
|
return 'long';
|
|
4393
4704
|
}
|
|
@@ -4400,7 +4711,7 @@ function readAsciiStringOrClassId(reader) {
|
|
|
4400
4711
|
return (0, psdReader_1.readAsciiString)(reader, length || 4);
|
|
4401
4712
|
}
|
|
4402
4713
|
function writeAsciiStringOrClassId(writer, value) {
|
|
4403
|
-
if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list') {
|
|
4714
|
+
if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list' && value !== 'json') {
|
|
4404
4715
|
// write classId
|
|
4405
4716
|
(0, psdWriter_1.writeInt32)(writer, 0);
|
|
4406
4717
|
(0, psdWriter_1.writeSignature)(writer, value);
|
|
@@ -4428,12 +4739,20 @@ function readDescriptorStructure(reader, includeClass) {
|
|
|
4428
4739
|
}
|
|
4429
4740
|
return object;
|
|
4430
4741
|
}
|
|
4742
|
+
exports.outputSettingsRoot = 'outputSettings';
|
|
4431
4743
|
function writeDescriptorStructure(writer, name, classId, value, root) {
|
|
4432
4744
|
if (logErrors && !classId)
|
|
4433
4745
|
console.log('Missing classId for: ', name, classId, value);
|
|
4434
4746
|
// write class structure
|
|
4435
4747
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
|
|
4436
|
-
|
|
4748
|
+
if (root === exports.outputSettingsRoot && classId === 'null') {
|
|
4749
|
+
// Photoshop writes 'null' class id as 4 character string in save for web output settings
|
|
4750
|
+
(0, psdWriter_1.writeInt32)(writer, 4);
|
|
4751
|
+
(0, psdWriter_1.writeSignature)(writer, classId);
|
|
4752
|
+
}
|
|
4753
|
+
else {
|
|
4754
|
+
writeAsciiStringOrClassId(writer, classId);
|
|
4755
|
+
}
|
|
4437
4756
|
const allKeys = Object.keys(value);
|
|
4438
4757
|
const keys = allKeys.filter(key => key !== '_name' && key !== '_classID' && value[key] !== undefined);
|
|
4439
4758
|
(0, psdWriter_1.writeUint32)(writer, keys.length);
|
|
@@ -4543,12 +4862,17 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
|
|
|
4543
4862
|
else if (key === 'bounds' && root === 'quiltWarp') {
|
|
4544
4863
|
extType = makeType('', 'classFloatRect');
|
|
4545
4864
|
}
|
|
4865
|
+
// guess color class from its fields (colors created by serializeColor always have _classID set)
|
|
4546
4866
|
if (extType && extType.classID === 'RGBC') {
|
|
4547
4867
|
if ('H ' in value[key])
|
|
4548
4868
|
extType = { classID: 'HSBC', name: '' };
|
|
4549
|
-
|
|
4869
|
+
else if ('Cyn ' in value[key])
|
|
4870
|
+
extType = { classID: 'CMYC', name: '' };
|
|
4871
|
+
else if ('Lmnc' in value[key])
|
|
4872
|
+
extType = { classID: 'LbCl', name: '' };
|
|
4873
|
+
else if ('Gry ' in value[key])
|
|
4874
|
+
extType = { classID: 'Grsc', name: '' };
|
|
4550
4875
|
}
|
|
4551
|
-
type = getRecordedOSType(value[key], type);
|
|
4552
4876
|
if (!type)
|
|
4553
4877
|
type = guessOSType(value[key]);
|
|
4554
4878
|
writeAsciiStringOrClassId(writer, key);
|
|
@@ -4563,9 +4887,8 @@ function readOSType(reader, type, includeClass) {
|
|
|
4563
4887
|
case 'obj ': // Reference
|
|
4564
4888
|
return readReferenceStructure(reader);
|
|
4565
4889
|
case 'Objc': // Descriptor
|
|
4566
|
-
return readDescriptorStructure(reader, includeClass);
|
|
4567
4890
|
case 'GlbO': // GlobalObject same as Descriptor
|
|
4568
|
-
return
|
|
4891
|
+
return readDescriptorStructure(reader, includeClass);
|
|
4569
4892
|
case 'VlLs': { // List
|
|
4570
4893
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4571
4894
|
const items = [];
|
|
@@ -4590,7 +4913,7 @@ function readOSType(reader, type, includeClass) {
|
|
|
4590
4913
|
const value = (0, psdReader_1.readFloat32)(reader);
|
|
4591
4914
|
if (!unitsMap[units])
|
|
4592
4915
|
throw new Error(`Invalid units: ${units}`);
|
|
4593
|
-
return
|
|
4916
|
+
return { units: unitsMap[units], value };
|
|
4594
4917
|
}
|
|
4595
4918
|
case 'TEXT': // String
|
|
4596
4919
|
return (0, psdReader_1.readUnicodeString)(reader);
|
|
@@ -4604,13 +4927,13 @@ function readOSType(reader, type, includeClass) {
|
|
|
4604
4927
|
case 'comp': { // Large Integer
|
|
4605
4928
|
const low = (0, psdReader_1.readUint32)(reader);
|
|
4606
4929
|
const high = (0, psdReader_1.readUint32)(reader);
|
|
4607
|
-
return
|
|
4930
|
+
return { low, high };
|
|
4608
4931
|
}
|
|
4609
4932
|
case 'bool': // Boolean
|
|
4610
4933
|
return !!(0, psdReader_1.readUint8)(reader);
|
|
4611
4934
|
case 'type': // Class
|
|
4612
4935
|
case 'GlbC': // Class
|
|
4613
|
-
return
|
|
4936
|
+
return readClassStructure(reader);
|
|
4614
4937
|
case 'alis': { // Alias
|
|
4615
4938
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4616
4939
|
return (0, psdReader_1.readAsciiString)(reader, length);
|
|
@@ -4622,21 +4945,21 @@ function readOSType(reader, type, includeClass) {
|
|
|
4622
4945
|
case 'ObAr': { // Object array
|
|
4623
4946
|
(0, psdReader_1.readInt32)(reader); // version: 16
|
|
4624
4947
|
(0, psdReader_1.readUnicodeString)(reader); // name: ''
|
|
4625
|
-
|
|
4948
|
+
readAsciiStringOrClassId(reader); // classID: 'rationalPoint'
|
|
4626
4949
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4627
4950
|
const items = [];
|
|
4628
4951
|
for (let i = 0; i < length; i++) {
|
|
4629
4952
|
const type1 = readAsciiStringOrClassId(reader); // type Hrzn | Vrtc
|
|
4630
|
-
|
|
4631
|
-
|
|
4953
|
+
(0, psdReader_1.readSignature)(reader); // UnFl
|
|
4954
|
+
(0, psdReader_1.readSignature)(reader); // units ? '#Pxl'
|
|
4632
4955
|
const valuesCount = (0, psdReader_1.readInt32)(reader);
|
|
4633
4956
|
const values = [];
|
|
4634
4957
|
for (let j = 0; j < valuesCount; j++) {
|
|
4635
4958
|
values.push((0, psdReader_1.readFloat64)(reader));
|
|
4636
4959
|
}
|
|
4637
|
-
items.push(
|
|
4960
|
+
items.push({ type: type1, values });
|
|
4638
4961
|
}
|
|
4639
|
-
return
|
|
4962
|
+
return items;
|
|
4640
4963
|
}
|
|
4641
4964
|
case 'Pth ': { // File path
|
|
4642
4965
|
/*const length =*/ (0, psdReader_1.readInt32)(reader); // total size of all fields below
|
|
@@ -4656,7 +4979,7 @@ const ObArTypes = {
|
|
|
4656
4979
|
quiltSliceY: 'UntF',
|
|
4657
4980
|
};
|
|
4658
4981
|
function writeOSType(writer, type, value, key, extType, root) {
|
|
4659
|
-
var _a
|
|
4982
|
+
var _a;
|
|
4660
4983
|
switch (type) {
|
|
4661
4984
|
case 'obj ': // Reference
|
|
4662
4985
|
writeReferenceStructure(writer, key, value);
|
|
@@ -4677,7 +5000,7 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4677
5000
|
throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4678
5001
|
(0, psdWriter_1.writeInt32)(writer, value.length);
|
|
4679
5002
|
for (let i = 0; i < value.length; i++) {
|
|
4680
|
-
const type = (_a =
|
|
5003
|
+
const type = (_a = fieldToArrayType[key]) !== null && _a !== void 0 ? _a : guessOSType(value[i]);
|
|
4681
5004
|
(0, psdWriter_1.writeSignature)(writer, type || 'long');
|
|
4682
5005
|
writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
|
|
4683
5006
|
if (logErrors && !type)
|
|
@@ -4751,16 +5074,15 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4751
5074
|
case 'ObAr': { // Object array
|
|
4752
5075
|
(0, psdWriter_1.writeInt32)(writer, 16); // version
|
|
4753
5076
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, ''); // name
|
|
4754
|
-
const type =
|
|
5077
|
+
const type = ObArTypes[key];
|
|
4755
5078
|
if (!type)
|
|
4756
5079
|
throw new Error(`Not implemented ObArType for: ${key}`);
|
|
4757
5080
|
writeAsciiStringOrClassId(writer, type);
|
|
4758
5081
|
(0, psdWriter_1.writeInt32)(writer, value.length);
|
|
4759
5082
|
for (let i = 0; i < value.length; i++) {
|
|
4760
|
-
const info = getHidden(value[i], obArInfoKey);
|
|
4761
5083
|
writeAsciiStringOrClassId(writer, value[i].type); // Hrzn | Vrtc
|
|
4762
|
-
(0, psdWriter_1.writeSignature)(writer,
|
|
4763
|
-
(0, psdWriter_1.writeSignature)(writer,
|
|
5084
|
+
(0, psdWriter_1.writeSignature)(writer, 'UnFl');
|
|
5085
|
+
(0, psdWriter_1.writeSignature)(writer, '#Pxl');
|
|
4764
5086
|
(0, psdWriter_1.writeInt32)(writer, value[i].values.length);
|
|
4765
5087
|
for (let j = 0; j < value[i].values.length; j++) {
|
|
4766
5088
|
(0, psdWriter_1.writeFloat64)(writer, value[i].values[j]);
|
|
@@ -4769,83 +5091,60 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4769
5091
|
break;
|
|
4770
5092
|
}
|
|
4771
5093
|
case 'Pth ': { // File path
|
|
4772
|
-
const
|
|
5094
|
+
const path = value.path + '\0'; // Photoshop stores trailing null character (stripped when reading)
|
|
5095
|
+
const length = 4 + 4 + 4 + path.length * 2;
|
|
4773
5096
|
(0, psdWriter_1.writeInt32)(writer, length);
|
|
4774
5097
|
(0, psdWriter_1.writeSignature)(writer, value.sig);
|
|
4775
5098
|
(0, psdWriter_1.writeInt32LE)(writer, length);
|
|
4776
|
-
(0, psdWriter_1.writeInt32LE)(writer,
|
|
4777
|
-
(0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer,
|
|
5099
|
+
(0, psdWriter_1.writeInt32LE)(writer, path.length);
|
|
5100
|
+
(0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer, path);
|
|
4778
5101
|
break;
|
|
4779
5102
|
}
|
|
4780
5103
|
default:
|
|
4781
5104
|
throw new Error(`Not implemented descriptor OSType: ${type}`);
|
|
4782
5105
|
}
|
|
4783
5106
|
}
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
case 'Clss': return { name: item.name || '', classID: item.classID };
|
|
4788
|
-
case 'Enmr': return `${item.typeID}.${item.enumValue}`;
|
|
4789
|
-
default: return item.value;
|
|
4790
|
-
}
|
|
4791
|
-
}
|
|
4792
|
-
function referenceItemMatches(item, value) {
|
|
4793
|
-
if (!item)
|
|
4794
|
-
return false;
|
|
4795
|
-
const expected = referenceItemToValue(item);
|
|
4796
|
-
if (expected && typeof expected === 'object') {
|
|
4797
|
-
return !!value && typeof value === 'object' && value.name === expected.name && value.classID === expected.classID;
|
|
4798
|
-
}
|
|
4799
|
-
return expected === value;
|
|
4800
|
-
}
|
|
4801
|
-
// Attaches information about how each item of reference should be written (class IDs, reference types),
|
|
4802
|
-
// the public value of the array stays the same (array of strings/numbers/class objects)
|
|
4803
|
-
function createDescriptorReference(items) {
|
|
4804
|
-
return setHidden(items.map(referenceItemToValue), referenceInfoKey, items);
|
|
5107
|
+
const referenceTypes = ['prop', 'Clss', 'Enmr', 'rele', 'Idnt', 'indx', 'name'];
|
|
5108
|
+
function isReferenceItem(value) {
|
|
5109
|
+
return !!value && typeof value === 'object' && referenceTypes.indexOf(value.type) !== -1;
|
|
4805
5110
|
}
|
|
4806
5111
|
function readReferenceStructure(reader) {
|
|
4807
5112
|
const itemsCount = (0, psdReader_1.readInt32)(reader);
|
|
4808
|
-
const
|
|
5113
|
+
const items = [];
|
|
4809
5114
|
for (let i = 0; i < itemsCount; i++) {
|
|
4810
5115
|
const type = (0, psdReader_1.readSignature)(reader);
|
|
4811
5116
|
switch (type) {
|
|
4812
|
-
case 'prop':
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
infos.push({ type, name, classID, keyID });
|
|
5117
|
+
case 'prop': // Property
|
|
5118
|
+
readClassStructure(reader);
|
|
5119
|
+
items.push(readAsciiStringOrClassId(reader));
|
|
4816
5120
|
break;
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
const { name, classID } = readClassStructure(reader);
|
|
4820
|
-
infos.push({ type, name, classID });
|
|
5121
|
+
case 'Clss': // Class
|
|
5122
|
+
items.push(readClassStructure(reader));
|
|
4821
5123
|
break;
|
|
4822
|
-
}
|
|
4823
5124
|
case 'Enmr': { // Enumerated Reference
|
|
4824
|
-
|
|
5125
|
+
readClassStructure(reader);
|
|
4825
5126
|
const typeID = readAsciiStringOrClassId(reader);
|
|
4826
5127
|
const enumValue = readAsciiStringOrClassId(reader);
|
|
4827
|
-
|
|
5128
|
+
items.push(`${typeID}.${enumValue}`);
|
|
4828
5129
|
break;
|
|
4829
5130
|
}
|
|
4830
|
-
case 'rele':
|
|
4831
|
-
|
|
4832
|
-
|
|
5131
|
+
case 'rele': // Offset
|
|
5132
|
+
readClassStructure(reader);
|
|
5133
|
+
items.push((0, psdReader_1.readUint32)(reader));
|
|
4833
5134
|
break;
|
|
4834
|
-
}
|
|
4835
5135
|
case 'Idnt': // Identifier
|
|
4836
5136
|
case 'indx': // Index
|
|
4837
|
-
|
|
5137
|
+
items.push((0, psdReader_1.readInt32)(reader));
|
|
4838
5138
|
break;
|
|
4839
|
-
case 'name':
|
|
4840
|
-
|
|
4841
|
-
|
|
5139
|
+
case 'name': // Name
|
|
5140
|
+
readClassStructure(reader);
|
|
5141
|
+
items.push((0, psdReader_1.readUnicodeString)(reader));
|
|
4842
5142
|
break;
|
|
4843
|
-
}
|
|
4844
5143
|
default:
|
|
4845
5144
|
throw new Error(`Invalid descriptor reference type: ${type}`);
|
|
4846
5145
|
}
|
|
4847
5146
|
}
|
|
4848
|
-
return
|
|
5147
|
+
return items;
|
|
4849
5148
|
}
|
|
4850
5149
|
function guessReferenceItem(value) {
|
|
4851
5150
|
if (typeof value === 'string') {
|
|
@@ -4853,17 +5152,17 @@ function guessReferenceItem(value) {
|
|
|
4853
5152
|
// (values like 'My.Path' or 'Logo.v2' can't be typeID/enum value, so they are written as name references)
|
|
4854
5153
|
const match = /^([a-z ]{4}|[a-z]{5,})\.([a-z ]+)$/i.exec(value);
|
|
4855
5154
|
if (match) {
|
|
4856
|
-
return { type: 'Enmr',
|
|
5155
|
+
return { type: 'Enmr', _name: '', _classID: match[1], typeID: match[1], enumValue: match[2] };
|
|
4857
5156
|
}
|
|
4858
5157
|
else {
|
|
4859
|
-
return { type: 'name',
|
|
5158
|
+
return { type: 'name', _name: '', _classID: 'Lyr ', value };
|
|
4860
5159
|
}
|
|
4861
5160
|
}
|
|
4862
5161
|
else if (typeof value === 'number') {
|
|
4863
5162
|
return { type: 'Idnt', value };
|
|
4864
5163
|
}
|
|
4865
5164
|
else if (value && typeof value === 'object' && typeof value.classID === 'string') {
|
|
4866
|
-
return { type: 'Clss',
|
|
5165
|
+
return { type: 'Clss', _name: value.name || '', _classID: value.classID };
|
|
4867
5166
|
}
|
|
4868
5167
|
else {
|
|
4869
5168
|
throw new Error(`Invalid descriptor reference value: ${JSON.stringify(value)}`);
|
|
@@ -4872,41 +5171,35 @@ function guessReferenceItem(value) {
|
|
|
4872
5171
|
// path selection state (image resource 1088) is a reference to paths, enumerated references there use 'Path' class
|
|
4873
5172
|
// (name references use 'Lyr ' class, they reference layer of the vector mask)
|
|
4874
5173
|
function pathSelectionStateToReference(items) {
|
|
4875
|
-
|
|
4876
|
-
return createDescriptorReference(items.map((value, i) => {
|
|
4877
|
-
if (referenceItemMatches(infos === null || infos === void 0 ? void 0 : infos[i], value))
|
|
4878
|
-
return infos[i]; // keep information read from the file
|
|
5174
|
+
return items.map(value => {
|
|
4879
5175
|
const item = guessReferenceItem(value);
|
|
4880
5176
|
if (item.type === 'Enmr')
|
|
4881
|
-
item.
|
|
5177
|
+
item._classID = 'Path';
|
|
4882
5178
|
return item;
|
|
4883
|
-
})
|
|
5179
|
+
});
|
|
4884
5180
|
}
|
|
4885
5181
|
function writeReferenceStructure(writer, _key, items) {
|
|
4886
5182
|
if (!Array.isArray(items))
|
|
4887
5183
|
throw new Error(`Invalid reference value: ${JSON.stringify(items)}, key: ${_key}`);
|
|
4888
|
-
const infos = getHidden(items, referenceInfoKey);
|
|
4889
5184
|
(0, psdWriter_1.writeInt32)(writer, items.length);
|
|
4890
|
-
for (
|
|
4891
|
-
const
|
|
4892
|
-
const recorded = infos === null || infos === void 0 ? void 0 : infos[i];
|
|
4893
|
-
const item = referenceItemMatches(recorded, value) ? recorded : guessReferenceItem(value);
|
|
5185
|
+
for (const value of items) {
|
|
5186
|
+
const item = isReferenceItem(value) ? value : guessReferenceItem(value);
|
|
4894
5187
|
(0, psdWriter_1.writeSignature)(writer, item.type);
|
|
4895
5188
|
switch (item.type) {
|
|
4896
5189
|
case 'prop': // Property
|
|
4897
|
-
writeClassStructure(writer, item.
|
|
5190
|
+
writeClassStructure(writer, item._name || '', item._classID);
|
|
4898
5191
|
writeAsciiStringOrClassId(writer, item.keyID);
|
|
4899
5192
|
break;
|
|
4900
5193
|
case 'Clss': // Class
|
|
4901
|
-
writeClassStructure(writer, item.
|
|
5194
|
+
writeClassStructure(writer, item._name || '', item._classID);
|
|
4902
5195
|
break;
|
|
4903
5196
|
case 'Enmr': // Enumerated Reference
|
|
4904
|
-
writeClassStructure(writer, item.
|
|
5197
|
+
writeClassStructure(writer, item._name || '', item._classID);
|
|
4905
5198
|
writeAsciiStringOrClassId(writer, item.typeID);
|
|
4906
5199
|
writeAsciiStringOrClassId(writer, item.enumValue);
|
|
4907
5200
|
break;
|
|
4908
5201
|
case 'rele': // Offset
|
|
4909
|
-
writeClassStructure(writer, item.
|
|
5202
|
+
writeClassStructure(writer, item._name || '', item._classID);
|
|
4910
5203
|
(0, psdWriter_1.writeUint32)(writer, item.value);
|
|
4911
5204
|
break;
|
|
4912
5205
|
case 'Idnt': // Identifier
|
|
@@ -4914,7 +5207,7 @@ function writeReferenceStructure(writer, _key, items) {
|
|
|
4914
5207
|
(0, psdWriter_1.writeInt32)(writer, item.value);
|
|
4915
5208
|
break;
|
|
4916
5209
|
case 'name': // Name
|
|
4917
|
-
writeClassStructure(writer, item.
|
|
5210
|
+
writeClassStructure(writer, item._name || '', item._classID);
|
|
4918
5211
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, `${item.value}`);
|
|
4919
5212
|
break;
|
|
4920
5213
|
default:
|
|
@@ -4973,7 +5266,7 @@ function parseFxObject(fx) {
|
|
|
4973
5266
|
fillType: exports.FrFl.decode(fx.PntT),
|
|
4974
5267
|
blendMode: exports.BlnM.decode(fx['Md ']),
|
|
4975
5268
|
opacity: parsePercent(fx.Opct),
|
|
4976
|
-
size:
|
|
5269
|
+
size: parseUnitsOrNumber(fx['Sz ']), // stored as number (pixels) in old versions
|
|
4977
5270
|
};
|
|
4978
5271
|
if (fx.present !== undefined)
|
|
4979
5272
|
stroke.present = fx.present;
|
|
@@ -5078,11 +5371,11 @@ function serializeEffects(e, log, multi) {
|
|
|
5078
5371
|
}
|
|
5079
5372
|
function parseEffects(info, log) {
|
|
5080
5373
|
const effects = {};
|
|
5081
|
-
const { masterFXSwitch, DrSh, dropShadowMulti, IrSh, innerShadowMulti, OrGl, IrGl, ebbl, SoFi, solidFillMulti, patternFill, GrFl, gradientFillMulti, ChFX, FrFX, frameFXMulti, numModifyingFX } =
|
|
5374
|
+
const _a = info, { _name, _classID, 'Scl ': scale, masterFXSwitch, DrSh, dropShadowMulti, IrSh, innerShadowMulti, OrGl, IrGl, ebbl, SoFi, solidFillMulti, patternFill, GrFl, gradientFillMulti, ChFX, FrFX, frameFXMulti, numModifyingFX } = _a, rest = __rest(_a, ["_name", "_classID", 'Scl ', "masterFXSwitch", "DrSh", "dropShadowMulti", "IrSh", "innerShadowMulti", "OrGl", "IrGl", "ebbl", "SoFi", "solidFillMulti", "patternFill", "GrFl", "gradientFillMulti", "ChFX", "FrFX", "frameFXMulti", "numModifyingFX"]);
|
|
5082
5375
|
if (!masterFXSwitch)
|
|
5083
5376
|
effects.disabled = true;
|
|
5084
|
-
if (
|
|
5085
|
-
effects.scale = parsePercent(
|
|
5377
|
+
if (scale)
|
|
5378
|
+
effects.scale = parsePercent(scale);
|
|
5086
5379
|
if (DrSh)
|
|
5087
5380
|
effects.dropShadow = [parseEffectObject(DrSh, log)];
|
|
5088
5381
|
if (dropShadowMulti)
|
|
@@ -5096,7 +5389,7 @@ function parseEffects(info, log) {
|
|
|
5096
5389
|
if (IrGl)
|
|
5097
5390
|
effects.innerGlow = parseEffectObject(IrGl, log);
|
|
5098
5391
|
if (ebbl)
|
|
5099
|
-
effects.bevel = parseEffectObject(ebbl, log);
|
|
5392
|
+
effects.bevel = parseEffectObject(ebbl, log, 'bevel');
|
|
5100
5393
|
if (SoFi)
|
|
5101
5394
|
effects.solidFill = [parseEffectObject(SoFi, log)];
|
|
5102
5395
|
if (solidFillMulti)
|
|
@@ -5113,7 +5406,7 @@ function parseEffects(info, log) {
|
|
|
5113
5406
|
effects.stroke = [parseFxObject(FrFX)];
|
|
5114
5407
|
if (frameFXMulti)
|
|
5115
5408
|
effects.stroke = frameFXMulti.map(i => parseFxObject(i));
|
|
5116
|
-
if (log && Object.keys(rest).length
|
|
5409
|
+
if (log && Object.keys(rest).length)
|
|
5117
5410
|
console.log('Unhandled effect keys:', rest);
|
|
5118
5411
|
return effects;
|
|
5119
5412
|
}
|
|
@@ -5222,7 +5515,7 @@ function serializeTrackList(tracks) {
|
|
|
5222
5515
|
}
|
|
5223
5516
|
return trackList;
|
|
5224
5517
|
}
|
|
5225
|
-
function parseEffectObject(obj, reportErrors) {
|
|
5518
|
+
function parseEffectObject(obj, reportErrors, objName) {
|
|
5226
5519
|
const result = {};
|
|
5227
5520
|
for (const key of Object.keys(obj)) {
|
|
5228
5521
|
const val = obj[key];
|
|
@@ -5287,7 +5580,8 @@ function parseEffectObject(obj, reportErrors) {
|
|
|
5287
5580
|
case 'Type':
|
|
5288
5581
|
result.type = exports.GrdT.decode(val);
|
|
5289
5582
|
break;
|
|
5290
|
-
case 'gs99':
|
|
5583
|
+
case 'gs99': // gradient overlay
|
|
5584
|
+
case 'gradientsInterpolationMethod': // glows
|
|
5291
5585
|
result.interpolationMethod = exports.gradientInterpolationMethodType.decode(val);
|
|
5292
5586
|
break;
|
|
5293
5587
|
case 'Opct':
|
|
@@ -5339,18 +5633,26 @@ function parseEffectObject(obj, reportErrors) {
|
|
|
5339
5633
|
result.pattern = { name: val['Nm '], id: val.Idnt };
|
|
5340
5634
|
break;
|
|
5341
5635
|
case 'phase':
|
|
5342
|
-
result.phase =
|
|
5636
|
+
result.phase = parsePhase(val);
|
|
5343
5637
|
break;
|
|
5344
5638
|
case 'Ofst':
|
|
5345
5639
|
result.offset = { x: parsePercent(val.Hrzn), y: parsePercent(val.Vrtc) };
|
|
5346
5640
|
break;
|
|
5347
5641
|
case 'MpgS':
|
|
5348
|
-
case 'TrnS':
|
|
5349
|
-
|
|
5642
|
+
case 'TrnS': {
|
|
5643
|
+
const contour = {
|
|
5350
5644
|
name: val['Nm '],
|
|
5351
5645
|
curve: val['Crv '].map(p => ({ x: p.Hrzn, y: p.Vrtc })),
|
|
5352
5646
|
};
|
|
5647
|
+
// bevel can have both: gloss contour (TrnS) and contour of the shape (MpgS)
|
|
5648
|
+
if (objName === 'bevel' && key === 'MpgS') {
|
|
5649
|
+
result.shapeContour = contour;
|
|
5650
|
+
}
|
|
5651
|
+
else {
|
|
5652
|
+
result.contour = contour;
|
|
5653
|
+
}
|
|
5353
5654
|
break;
|
|
5655
|
+
}
|
|
5354
5656
|
case 'Grad':
|
|
5355
5657
|
result.gradient = parseGradient(val);
|
|
5356
5658
|
break;
|
|
@@ -5445,7 +5747,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
|
|
|
5445
5747
|
result.Type = exports.GrdT.encode(val);
|
|
5446
5748
|
break;
|
|
5447
5749
|
case 'interpolationMethod':
|
|
5448
|
-
result
|
|
5750
|
+
result[(objName === 'outerGlow' || objName === 'innerGlow') ? 'gradientsInterpolationMethod' : 'gs99'] = exports.gradientInterpolationMethodType.encode(val);
|
|
5449
5751
|
break;
|
|
5450
5752
|
case 'opacity':
|
|
5451
5753
|
result.Opct = unitsPercent(val);
|
|
@@ -5501,15 +5803,14 @@ function serializeEffectObject(obj, objName, reportErrors) {
|
|
|
5501
5803
|
result.phase = { Hrzn: val.x, Vrtc: val.y };
|
|
5502
5804
|
break;
|
|
5503
5805
|
case 'offset':
|
|
5504
|
-
result.Ofst = { Hrzn:
|
|
5806
|
+
result.Ofst = { Hrzn: unitsPercentF(val.x), Vrtc: unitsPercentF(val.y) };
|
|
5505
5807
|
break;
|
|
5506
|
-
case 'contour':
|
|
5507
|
-
result[objName === 'satin' ? 'MpgS' : 'TrnS'] =
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5808
|
+
case 'contour':
|
|
5809
|
+
result[objName === 'satin' ? 'MpgS' : 'TrnS'] = serializeContour(val);
|
|
5810
|
+
break;
|
|
5811
|
+
case 'shapeContour':
|
|
5812
|
+
result.MpgS = serializeContour(val);
|
|
5511
5813
|
break;
|
|
5512
|
-
}
|
|
5513
5814
|
case 'gradient':
|
|
5514
5815
|
result.Grad = serializeGradient(val);
|
|
5515
5816
|
break;
|
|
@@ -5527,6 +5828,12 @@ function serializeEffectObject(obj, objName, reportErrors) {
|
|
|
5527
5828
|
}
|
|
5528
5829
|
return result;
|
|
5529
5830
|
}
|
|
5831
|
+
function serializeContour(contour) {
|
|
5832
|
+
return {
|
|
5833
|
+
'Nm ': contour.name,
|
|
5834
|
+
'Crv ': contour.curve.map(p => ({ Hrzn: p.x, Vrtc: p.y })),
|
|
5835
|
+
};
|
|
5836
|
+
}
|
|
5530
5837
|
function parseGradient(grad) {
|
|
5531
5838
|
if (grad.GrdF === 'GrdF.CstS') {
|
|
5532
5839
|
// stop locations are always in 0..4096 range, independent of smoothness (Intr)
|
|
@@ -5535,11 +5842,22 @@ function parseGradient(grad) {
|
|
|
5535
5842
|
type: 'solid',
|
|
5536
5843
|
name: grad['Nm '],
|
|
5537
5844
|
smoothness: grad.Intr / 4096,
|
|
5538
|
-
colorStops: grad.Clrs.map(s =>
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5845
|
+
colorStops: grad.Clrs.map(s => {
|
|
5846
|
+
const stop = {
|
|
5847
|
+
color: s['Clr '] ? parseColor(s['Clr ']) : { r: 0, g: 0, b: 0 },
|
|
5848
|
+
location: s.Lctn / samples,
|
|
5849
|
+
midpoint: s.Mdpn / 100,
|
|
5850
|
+
};
|
|
5851
|
+
if (s.Type) {
|
|
5852
|
+
try {
|
|
5853
|
+
const type = exports.Clry.decode(s.Type);
|
|
5854
|
+
if (type !== 'user')
|
|
5855
|
+
stop.type = type;
|
|
5856
|
+
}
|
|
5857
|
+
catch (_a) { } // unknown stop type, read as user color
|
|
5858
|
+
}
|
|
5859
|
+
return stop;
|
|
5860
|
+
}),
|
|
5543
5861
|
opacityStops: grad.Trns.map(s => ({
|
|
5544
5862
|
opacity: parsePercent(s.Opct),
|
|
5545
5863
|
location: s.Lctn / samples,
|
|
@@ -5571,18 +5889,18 @@ function serializeGradient(grad) {
|
|
|
5571
5889
|
GrdF: 'GrdF.CstS',
|
|
5572
5890
|
Intr: Math.round(((_a = grad.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096),
|
|
5573
5891
|
Clrs: grad.colorStops.map(s => {
|
|
5574
|
-
var _a;
|
|
5892
|
+
var _a, _b;
|
|
5575
5893
|
return ({
|
|
5576
5894
|
'Clr ': serializeColor(s.color),
|
|
5577
|
-
Type:
|
|
5895
|
+
Type: exports.Clry.encode((_a = s.type) !== null && _a !== void 0 ? _a : 'user'),
|
|
5578
5896
|
Lctn: Math.round(s.location * samples),
|
|
5579
|
-
Mdpn: Math.round(((
|
|
5897
|
+
Mdpn: Math.round(((_b = s.midpoint) !== null && _b !== void 0 ? _b : 0.5) * 100),
|
|
5580
5898
|
});
|
|
5581
5899
|
}),
|
|
5582
5900
|
Trns: grad.opacityStops.map(s => {
|
|
5583
5901
|
var _a;
|
|
5584
5902
|
return ({
|
|
5585
|
-
Opct:
|
|
5903
|
+
Opct: unitsPercentF(s.opacity),
|
|
5586
5904
|
Lctn: Math.round(s.location * samples),
|
|
5587
5905
|
Mdpn: Math.round(((_a = s.midpoint) !== null && _a !== void 0 ? _a : 0.5) * 100),
|
|
5588
5906
|
});
|
|
@@ -5626,6 +5944,13 @@ function parseGradientContent(descriptor) {
|
|
|
5626
5944
|
}
|
|
5627
5945
|
return result;
|
|
5628
5946
|
}
|
|
5947
|
+
// phase is usually stored as plain numbers, but some files store it as unit values
|
|
5948
|
+
function parsePhase({ Hrzn, Vrtc }) {
|
|
5949
|
+
return {
|
|
5950
|
+
x: typeof Hrzn === 'number' ? Hrzn : Hrzn.value,
|
|
5951
|
+
y: typeof Vrtc === 'number' ? Vrtc : Vrtc.value,
|
|
5952
|
+
};
|
|
5953
|
+
}
|
|
5629
5954
|
function parsePatternContent(descriptor) {
|
|
5630
5955
|
const result = {
|
|
5631
5956
|
name: descriptor.Ptrn['Nm '],
|
|
@@ -5634,7 +5959,11 @@ function parsePatternContent(descriptor) {
|
|
|
5634
5959
|
if (descriptor.Lnkd !== undefined)
|
|
5635
5960
|
result.linked = descriptor.Lnkd;
|
|
5636
5961
|
if (descriptor.phase !== undefined)
|
|
5637
|
-
result.phase =
|
|
5962
|
+
result.phase = parsePhase(descriptor.phase);
|
|
5963
|
+
if (descriptor['Scl '] !== undefined)
|
|
5964
|
+
result.scale = parsePercent(descriptor['Scl ']);
|
|
5965
|
+
if (descriptor.Angl !== undefined)
|
|
5966
|
+
result.angle = parseAngle(descriptor.Angl);
|
|
5638
5967
|
return result;
|
|
5639
5968
|
}
|
|
5640
5969
|
function parseVectorContent(descriptor) {
|
|
@@ -5665,11 +5994,11 @@ function serializeGradientContent(content) {
|
|
|
5665
5994
|
if (content.align !== undefined)
|
|
5666
5995
|
result.Algn = content.align;
|
|
5667
5996
|
if (content.scale !== undefined)
|
|
5668
|
-
result['Scl '] =
|
|
5997
|
+
result['Scl '] = unitsPercentF(content.scale);
|
|
5669
5998
|
if (content.offset) {
|
|
5670
5999
|
result.Ofst = {
|
|
5671
|
-
Hrzn:
|
|
5672
|
-
Vrtc:
|
|
6000
|
+
Hrzn: unitsPercentF(content.offset.x),
|
|
6001
|
+
Vrtc: unitsPercentF(content.offset.y),
|
|
5673
6002
|
};
|
|
5674
6003
|
}
|
|
5675
6004
|
result.Grad = serializeGradient(content);
|
|
@@ -5686,6 +6015,10 @@ function serializePatternContent(content) {
|
|
|
5686
6015
|
result.Lnkd = !!content.linked;
|
|
5687
6016
|
if (content.phase !== undefined)
|
|
5688
6017
|
result.phase = { Hrzn: content.phase.x, Vrtc: content.phase.y };
|
|
6018
|
+
if (content.scale !== undefined)
|
|
6019
|
+
result['Scl '] = unitsPercentF(content.scale);
|
|
6020
|
+
if (content.angle !== undefined)
|
|
6021
|
+
result.Angl = unitsAngle(content.angle);
|
|
5689
6022
|
return result;
|
|
5690
6023
|
}
|
|
5691
6024
|
function serializeVectorContent(content) {
|
|
@@ -5701,9 +6034,9 @@ function serializeVectorContent(content) {
|
|
|
5701
6034
|
}
|
|
5702
6035
|
// Descriptor color values: HSB saturation/brightness 0..100, CMYK 0..100, Gray 0..100, Lab L 0..100, a/b -128..127
|
|
5703
6036
|
// Color values (see psd.ts): HSB 0..1, CMYK 0..255, Gray 0..255, Lab L 0..1, a/b -1..1 (same as readColor/writeColor)
|
|
5704
|
-
const colorSourceKey = typeof Symbol !== 'undefined' ? Symbol('agPsdColorSource') : '__agPsdColorSource';
|
|
5705
6037
|
const colorConversions = {
|
|
5706
6038
|
// key: [descriptor -> color, color -> descriptor]
|
|
6039
|
+
'H ': [x => x / 360, x => x * 360], // angle
|
|
5707
6040
|
Strt: [x => x / 100, x => x * 100],
|
|
5708
6041
|
Brgh: [x => x / 100, x => x * 100],
|
|
5709
6042
|
'Cyn ': [x => x * 255 / 100, x => x * 100 / 255],
|
|
@@ -5731,22 +6064,18 @@ function colorToDescriptorValue(key, value) {
|
|
|
5731
6064
|
}
|
|
5732
6065
|
return result;
|
|
5733
6066
|
}
|
|
5734
|
-
function
|
|
5735
|
-
|
|
5736
|
-
if (keys.length !== Object.keys(b).length)
|
|
5737
|
-
return false;
|
|
5738
|
-
return keys.every(key => a[key] === b[key]);
|
|
6067
|
+
function isBookColor(color) {
|
|
6068
|
+
return color._classID === 'BkCl' || 'Bk ' in color || 'bookID' in color;
|
|
5739
6069
|
}
|
|
5740
6070
|
function parseColor(color) {
|
|
5741
|
-
let result;
|
|
5742
6071
|
if ('H ' in color) {
|
|
5743
|
-
|
|
6072
|
+
return { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
|
|
5744
6073
|
}
|
|
5745
6074
|
else if ('Rd ' in color) {
|
|
5746
6075
|
return { r: color['Rd '], g: color['Grn '], b: color['Bl '] };
|
|
5747
6076
|
}
|
|
5748
6077
|
else if ('Cyn ' in color) {
|
|
5749
|
-
|
|
6078
|
+
return {
|
|
5750
6079
|
c: color['Cyn '] * 255 / 100,
|
|
5751
6080
|
m: color.Mgnt * 255 / 100,
|
|
5752
6081
|
y: color['Ylw '] * 255 / 100,
|
|
@@ -5754,21 +6083,22 @@ function parseColor(color) {
|
|
|
5754
6083
|
};
|
|
5755
6084
|
}
|
|
5756
6085
|
else if ('Gry ' in color) {
|
|
5757
|
-
|
|
6086
|
+
return { k: color['Gry '] * 255 / 100 };
|
|
5758
6087
|
}
|
|
5759
6088
|
else if ('Lmnc' in color) {
|
|
5760
|
-
|
|
6089
|
+
return { l: color.Lmnc / 100, a: (0, helpers_1.normalizeLabAB)(color['A ']), b: (0, helpers_1.normalizeLabAB)(color['B ']) };
|
|
5761
6090
|
}
|
|
5762
6091
|
else if ('redFloat' in color) {
|
|
5763
6092
|
return { fr: color.redFloat, fg: color.greenFloat, fb: color.blueFloat };
|
|
5764
6093
|
}
|
|
6094
|
+
else if (isBookColor(color)) {
|
|
6095
|
+
return { r: 0, g: 0, b: 0 }; // book (Pantone) colors are not supported
|
|
6096
|
+
}
|
|
5765
6097
|
else {
|
|
5766
6098
|
throw new Error('Unsupported color descriptor');
|
|
5767
6099
|
}
|
|
5768
|
-
// remember original descriptor values, so unmodified colors can be written back without conversion errors
|
|
5769
|
-
return setHidden(result, colorSourceKey, { color: Object.assign({}, result), descriptor: color });
|
|
5770
6100
|
}
|
|
5771
|
-
function
|
|
6101
|
+
function serializeColor(color) {
|
|
5772
6102
|
if (!color) {
|
|
5773
6103
|
return { _name: '', _classID: 'RGBC', 'Rd ': 0, 'Grn ': 0, 'Bl ': 0 };
|
|
5774
6104
|
}
|
|
@@ -5781,7 +6111,7 @@ function serializeColorValues(color) {
|
|
|
5781
6111
|
else if ('h' in color) {
|
|
5782
6112
|
return {
|
|
5783
6113
|
_name: '', _classID: 'HSBC',
|
|
5784
|
-
'H ': unitsAngle((color.h || 0)
|
|
6114
|
+
'H ': unitsAngle(colorToDescriptorValue('H ', color.h || 0)),
|
|
5785
6115
|
Strt: colorToDescriptorValue('Strt', color.s || 0),
|
|
5786
6116
|
Brgh: colorToDescriptorValue('Brgh', color.b || 0),
|
|
5787
6117
|
};
|
|
@@ -5807,21 +6137,8 @@ function serializeColorValues(color) {
|
|
|
5807
6137
|
return { _name: '', _classID: 'Grsc', 'Gry ': colorToDescriptorValue('Gry ', color.k || 0) };
|
|
5808
6138
|
}
|
|
5809
6139
|
else {
|
|
5810
|
-
throw new Error('Invalid color value');
|
|
5811
|
-
}
|
|
5812
|
-
}
|
|
5813
|
-
function serializeColor(color) {
|
|
5814
|
-
const result = serializeColorValues(color);
|
|
5815
|
-
const source = getHidden(color, colorSourceKey);
|
|
5816
|
-
if (source && shallowEqual(source.color, color)) {
|
|
5817
|
-
// color was not modified since it was read, use exact original values
|
|
5818
|
-
for (const key of Object.keys(result)) {
|
|
5819
|
-
if (colorConversions[key] && typeof source.descriptor[key] === 'number') {
|
|
5820
|
-
result[key] = source.descriptor[key];
|
|
5821
|
-
}
|
|
5822
|
-
}
|
|
6140
|
+
throw new Error('Invalid color value');
|
|
5823
6141
|
}
|
|
5824
|
-
return result;
|
|
5825
6142
|
}
|
|
5826
6143
|
function parseAngle(x) {
|
|
5827
6144
|
if (x === undefined)
|
|
@@ -5848,7 +6165,8 @@ function parsePercentOrAngle(x) {
|
|
|
5848
6165
|
}
|
|
5849
6166
|
function parseUnits({ units, value }) {
|
|
5850
6167
|
if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
|
|
5851
|
-
units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density'
|
|
6168
|
+
units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
|
|
6169
|
+
units !== 'Distance') {
|
|
5852
6170
|
throw new Error(`Invalid units: ${JSON.stringify({ units, value })}`);
|
|
5853
6171
|
}
|
|
5854
6172
|
return { value, units };
|
|
@@ -5881,7 +6199,8 @@ function unitsValue(x, key) {
|
|
|
5881
6199
|
if (typeof value !== 'number')
|
|
5882
6200
|
throw new Error(`Invalid value in ${JSON.stringify(x)} (key: ${key})`);
|
|
5883
6201
|
if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
|
|
5884
|
-
units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density'
|
|
6202
|
+
units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
|
|
6203
|
+
units !== 'Distance') {
|
|
5885
6204
|
throw new Error(`Invalid units in ${JSON.stringify(x)} (key: ${key})`);
|
|
5886
6205
|
}
|
|
5887
6206
|
return { units, value };
|
|
@@ -6009,6 +6328,11 @@ exports.gradientInterpolationMethodType = (0, helpers_1.createEnum)('gradientInt
|
|
|
6009
6328
|
smooth: 'Smoo',
|
|
6010
6329
|
// TODO: stripes
|
|
6011
6330
|
});
|
|
6331
|
+
exports.Clry = (0, helpers_1.createEnum)('Clry', 'user', {
|
|
6332
|
+
user: 'UsrS',
|
|
6333
|
+
foreground: 'FrgC',
|
|
6334
|
+
background: 'BckC',
|
|
6335
|
+
});
|
|
6012
6336
|
exports.ClrS = (0, helpers_1.createEnum)('ClrS', 'rgb', {
|
|
6013
6337
|
rgb: 'RGBC',
|
|
6014
6338
|
hsb: 'HSBl',
|
|
@@ -7293,7 +7617,7 @@ function decodeEngineData2(data) {
|
|
|
7293
7617
|
},{"./engineData":6}],8:[function(require,module,exports){
|
|
7294
7618
|
"use strict";
|
|
7295
7619
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7296
|
-
exports.createImageData = exports.createCanvas = exports.MaskParams = exports.LayerMaskFlags = exports.ColorSpace = exports.largeAdditionalInfoKeys = exports.
|
|
7620
|
+
exports.createImageData = exports.createCanvas = exports.MaskParams = exports.LayerMaskFlags = exports.ColorSpace = exports.largeAdditionalInfoKeys = exports.largeAdditionalInfoKeysObserved = exports.layerColors = exports.toBlendMode = exports.fromBlendMode = exports.MOCK_HANDLERS = void 0;
|
|
7297
7621
|
exports.revMap = revMap;
|
|
7298
7622
|
exports.createEnum = createEnum;
|
|
7299
7623
|
exports.offsetForChannel = offsetForChannel;
|
|
@@ -7312,7 +7636,6 @@ exports.initializeCanvas = initializeCanvas;
|
|
|
7312
7636
|
const pako_1 = require("pako");
|
|
7313
7637
|
const jpeg_1 = require("./jpeg");
|
|
7314
7638
|
exports.MOCK_HANDLERS = false;
|
|
7315
|
-
exports.RAW_IMAGE_DATA = false;
|
|
7316
7639
|
exports.fromBlendMode = {};
|
|
7317
7640
|
exports.toBlendMode = {
|
|
7318
7641
|
'pass': 'pass through',
|
|
@@ -7348,11 +7671,14 @@ Object.keys(exports.toBlendMode).forEach(key => exports.fromBlendMode[exports.to
|
|
|
7348
7671
|
exports.layerColors = [
|
|
7349
7672
|
'none', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'gray'
|
|
7350
7673
|
];
|
|
7674
|
+
// keys not listed in documentation that Photoshop writes with 64bit length in PSB files (with 8B64 signature)
|
|
7675
|
+
exports.largeAdditionalInfoKeysObserved = ['lnk3', 'lnkE', 'pths', 'extd', 'extn', 'FELS', 'artd'];
|
|
7351
7676
|
exports.largeAdditionalInfoKeys = [
|
|
7352
7677
|
// from documentation
|
|
7353
7678
|
'LMsk', 'Lr16', 'Lr32', 'Layr', 'Mt16', 'Mt32', 'Mtrn', 'Alph', 'FMsk', 'lnk2', 'FEid', 'FXid', 'PxSD',
|
|
7354
7679
|
// from guessing
|
|
7355
7680
|
'cinf',
|
|
7681
|
+
...exports.largeAdditionalInfoKeysObserved,
|
|
7356
7682
|
];
|
|
7357
7683
|
function revMap(map) {
|
|
7358
7684
|
const result = {};
|
|
@@ -7664,6 +7990,7 @@ function initializeCanvas(createCanvasMethod, createImageDataMethod) {
|
|
|
7664
7990
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7665
7991
|
exports.resourceHandlersMap = exports.resourceHandlers = void 0;
|
|
7666
7992
|
const base64_js_1 = require("base64-js");
|
|
7993
|
+
const additionalInfo_1 = require("./additionalInfo");
|
|
7667
7994
|
const psdReader_1 = require("./psdReader");
|
|
7668
7995
|
const psdWriter_1 = require("./psdWriter");
|
|
7669
7996
|
const helpers_1 = require("./helpers");
|
|
@@ -7671,10 +7998,12 @@ const utf8_1 = require("./utf8");
|
|
|
7671
7998
|
const descriptor_1 = require("./descriptor");
|
|
7672
7999
|
exports.resourceHandlers = [];
|
|
7673
8000
|
exports.resourceHandlersMap = {};
|
|
7674
|
-
function addHandler(key, has, read, write) {
|
|
7675
|
-
|
|
8001
|
+
function addHandler(key, has, read, write, options = {}) {
|
|
8002
|
+
var _a;
|
|
8003
|
+
const handler = { key, keyCount: (_a = options.keyCount) !== null && _a !== void 0 ? _a : 1, has, read, write, name: options.name };
|
|
7676
8004
|
exports.resourceHandlers.push(handler);
|
|
7677
|
-
|
|
8005
|
+
for (let i = 0; i < handler.keyCount; i++)
|
|
8006
|
+
exports.resourceHandlersMap[handler.key + i] = handler;
|
|
7678
8007
|
}
|
|
7679
8008
|
const LOG_MOCK_HANDLERS = false;
|
|
7680
8009
|
const RESOLUTION_UNITS = [undefined, 'PPI', 'PPCM'];
|
|
@@ -7692,27 +8021,18 @@ function byteAt(value, index) {
|
|
|
7692
8021
|
}
|
|
7693
8022
|
function readUtf8String(reader, length) {
|
|
7694
8023
|
const buffer = (0, psdReader_1.readBytes)(reader, length);
|
|
7695
|
-
return (0,
|
|
8024
|
+
return (0, psdReader_1.decodeUtf8)(reader, buffer);
|
|
7696
8025
|
}
|
|
7697
8026
|
function writeUtf8String(writer, value) {
|
|
7698
8027
|
const buffer = (0, utf8_1.encodeString)(value);
|
|
7699
8028
|
(0, psdWriter_1.writeBytes)(writer, buffer);
|
|
7700
8029
|
}
|
|
7701
|
-
let gbkDecoder;
|
|
7702
|
-
function getGbkDecoder() {
|
|
7703
|
-
if (gbkDecoder === undefined) {
|
|
7704
|
-
try {
|
|
7705
|
-
gbkDecoder = new TextDecoder('gbk');
|
|
7706
|
-
}
|
|
7707
|
-
catch (_a) {
|
|
7708
|
-
gbkDecoder = null;
|
|
7709
|
-
}
|
|
7710
|
-
}
|
|
7711
|
-
return gbkDecoder;
|
|
7712
|
-
}
|
|
7713
8030
|
function readEncodedString(reader) {
|
|
7714
8031
|
const length = (0, psdReader_1.readUint8)(reader);
|
|
7715
8032
|
const buffer = (0, psdReader_1.readBytes)(reader, length);
|
|
8033
|
+
return decodeEncodedString(reader, buffer);
|
|
8034
|
+
}
|
|
8035
|
+
function decodeEncodedString(reader, buffer) {
|
|
7716
8036
|
let notAscii = false;
|
|
7717
8037
|
for (let i = 0; i < buffer.byteLength; i++) {
|
|
7718
8038
|
if (buffer[i] & 0x80) {
|
|
@@ -7721,17 +8041,20 @@ function readEncodedString(reader) {
|
|
|
7721
8041
|
}
|
|
7722
8042
|
}
|
|
7723
8043
|
if (notAscii) {
|
|
7724
|
-
|
|
7725
|
-
if
|
|
7726
|
-
|
|
7727
|
-
|
|
8044
|
+
// encoding is ambiguous, many GBK strings are also valid UTF-8 and vice versa, GBK is preferred,
|
|
8045
|
+
// UTF-8 is only used if the string is not valid GBK
|
|
8046
|
+
for (const decoder of [(0, psdReader_1.getGbkStrictDecoder)(reader), (0, psdReader_1.getUtf8StrictDecoder)(reader)]) {
|
|
8047
|
+
if (decoder) {
|
|
8048
|
+
try {
|
|
8049
|
+
return decoder.decode(buffer);
|
|
8050
|
+
}
|
|
8051
|
+
catch (_a) { }
|
|
7728
8052
|
}
|
|
7729
|
-
catch (_a) { }
|
|
7730
8053
|
}
|
|
7731
8054
|
}
|
|
7732
|
-
return (0,
|
|
8055
|
+
return (0, psdReader_1.decodeUtf8)(reader, buffer);
|
|
7733
8056
|
}
|
|
7734
|
-
function
|
|
8057
|
+
function toShortAsciiString(value) {
|
|
7735
8058
|
let ascii = '';
|
|
7736
8059
|
for (let i = 0; i < value.length;) {
|
|
7737
8060
|
const code = value.codePointAt(i);
|
|
@@ -7739,19 +8062,19 @@ function writeEncodedString(writer, value) {
|
|
|
7739
8062
|
i += code > 0xffff ? 2 : 1; // skip low surrogate of astral characters
|
|
7740
8063
|
}
|
|
7741
8064
|
// length is stored in a single byte
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
8065
|
+
return ascii.length > 255 ? ascii.substring(0, 255) : ascii;
|
|
8066
|
+
}
|
|
8067
|
+
function writeEncodedString(writer, value) {
|
|
8068
|
+
const buffer = (0, utf8_1.encodeString)(toShortAsciiString(value));
|
|
7745
8069
|
(0, psdWriter_1.writeUint8)(writer, buffer.byteLength);
|
|
7746
8070
|
(0, psdWriter_1.writeBytes)(writer, buffer);
|
|
7747
8071
|
}
|
|
7748
|
-
|
|
8072
|
+
addHandler(1028, // IPTC-NAA record
|
|
7749
8073
|
// IPTC-NAA record
|
|
7750
|
-
target => target.
|
|
7751
|
-
|
|
7752
|
-
target._ir1028 = (0, psdReader_1.readBytes)(reader, left());
|
|
8074
|
+
target => target.iptcData !== undefined, (reader, target, left) => {
|
|
8075
|
+
target.iptcData = (0, psdReader_1.readBytes)(reader, left());
|
|
7753
8076
|
}, (writer, target) => {
|
|
7754
|
-
(0, psdWriter_1.writeBytes)(writer, target.
|
|
8077
|
+
(0, psdWriter_1.writeBytes)(writer, target.iptcData);
|
|
7755
8078
|
});
|
|
7756
8079
|
addHandler(1061, target => target.captionDigest !== undefined, (reader, target) => {
|
|
7757
8080
|
let captionDigest = '';
|
|
@@ -7777,12 +8100,12 @@ const Inte = (0, helpers_1.createEnum)('Inte', 'perceptual', {
|
|
|
7777
8100
|
'relative colorimetric': 'Clrm',
|
|
7778
8101
|
'absolute colorimetric': 'AClr',
|
|
7779
8102
|
});
|
|
7780
|
-
|
|
8103
|
+
addHandler(1085, // Windows DEVMODE. Variable OS specific info for Windows.
|
|
7781
8104
|
// Windows DEVMODE. Variable OS specific info for Windows.
|
|
7782
|
-
target => target.
|
|
7783
|
-
target.
|
|
8105
|
+
target => target.windowsDevMode !== undefined, (reader, target, left) => {
|
|
8106
|
+
target.windowsDevMode = (0, psdReader_1.readBytes)(reader, left());
|
|
7784
8107
|
}, (writer, target) => {
|
|
7785
|
-
(0, psdWriter_1.writeBytes)(writer, target.
|
|
8108
|
+
(0, psdWriter_1.writeBytes)(writer, target.windowsDevMode);
|
|
7786
8109
|
});
|
|
7787
8110
|
addHandler(1082, target => target.printInformation !== undefined, (reader, target) => {
|
|
7788
8111
|
var _a, _b;
|
|
@@ -7794,6 +8117,8 @@ addHandler(1082, target => target.printInformation !== undefined, (reader, targe
|
|
|
7794
8117
|
const info = target.printInformation;
|
|
7795
8118
|
if (desc.PstS !== undefined)
|
|
7796
8119
|
info.printerManagesColors = desc.PstS;
|
|
8120
|
+
if (desc.ClrS === 'ClrS.Grys')
|
|
8121
|
+
info.printerProfileColorSpace = 'grayscale';
|
|
7797
8122
|
if (desc['Nm '] !== undefined)
|
|
7798
8123
|
info.printerProfile = desc['Nm '];
|
|
7799
8124
|
if (desc.MpBl !== undefined)
|
|
@@ -7816,7 +8141,6 @@ addHandler(1082, target => target.printInformation !== undefined, (reader, targe
|
|
|
7816
8141
|
}
|
|
7817
8142
|
}
|
|
7818
8143
|
}, (writer, target) => {
|
|
7819
|
-
var _a, _b;
|
|
7820
8144
|
const info = target.printInformation;
|
|
7821
8145
|
const desc = {};
|
|
7822
8146
|
if (info.printerManagesColors) {
|
|
@@ -7825,11 +8149,12 @@ addHandler(1082, target => target.printInformation !== undefined, (reader, targe
|
|
|
7825
8149
|
else {
|
|
7826
8150
|
if (info.hardProof !== undefined)
|
|
7827
8151
|
desc.hardProof = !!info.hardProof;
|
|
7828
|
-
desc.ClrS = 'ClrS.
|
|
7829
|
-
|
|
8152
|
+
desc.ClrS = info.printerProfileColorSpace === 'grayscale' ? 'ClrS.Grys' : 'ClrS.RGBC';
|
|
8153
|
+
if (info.printerProfile !== undefined)
|
|
8154
|
+
desc['Nm '] = info.printerProfile;
|
|
7830
8155
|
}
|
|
7831
8156
|
desc.Inte = Inte.encode(info.renderingIntent);
|
|
7832
|
-
if (!info.printerManagesColors)
|
|
8157
|
+
if (!info.printerManagesColors && info.blackPointCompensation !== undefined)
|
|
7833
8158
|
desc.MpBl = !!info.blackPointCompensation;
|
|
7834
8159
|
desc.printSixteenBit = !!info.printSixteenBit;
|
|
7835
8160
|
desc.printerName = info.printerName || '';
|
|
@@ -7841,23 +8166,77 @@ addHandler(1082, target => target.printInformation !== undefined, (reader, targe
|
|
|
7841
8166
|
paperWhite: !!info.proofSetup.paperWhite,
|
|
7842
8167
|
};
|
|
7843
8168
|
}
|
|
7844
|
-
else {
|
|
8169
|
+
else if (info.proofSetup) {
|
|
7845
8170
|
desc.printProofSetup = {
|
|
7846
|
-
Bltn:
|
|
8171
|
+
Bltn: `builtinProof.${info.proofSetup.builtin || 'proofCMYK'}`,
|
|
7847
8172
|
};
|
|
7848
8173
|
}
|
|
7849
8174
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'printOutput', desc);
|
|
7850
8175
|
});
|
|
7851
|
-
|
|
8176
|
+
addHandler(1083, // Print style
|
|
7852
8177
|
// Print style
|
|
7853
|
-
target => target.
|
|
7854
|
-
|
|
7855
|
-
target.
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
8178
|
+
target => target.printStyle !== undefined, (reader, target) => {
|
|
8179
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
8180
|
+
target.printStyle = {
|
|
8181
|
+
caption: desc.Cptn,
|
|
8182
|
+
calibrationBars: desc.Clbr,
|
|
8183
|
+
registrationMarks: desc.RgsM,
|
|
8184
|
+
cornerCropMarks: desc.CrnC,
|
|
8185
|
+
centerCropMarks: desc.CntC,
|
|
8186
|
+
labels: desc.Lbls,
|
|
8187
|
+
negative: desc.Ngtv,
|
|
8188
|
+
emulsionDown: desc.EmlD,
|
|
8189
|
+
interpolate: desc.Intr,
|
|
8190
|
+
backgroundColor: (0, descriptor_1.parseColor)(desc.Bckg),
|
|
8191
|
+
border: (0, descriptor_1.parseUnits)(desc.BrdT),
|
|
8192
|
+
bleed: (0, descriptor_1.parseUnits)(desc['Bld ']),
|
|
8193
|
+
resolution: (0, descriptor_1.parseUnits)(desc.Rslt),
|
|
8194
|
+
vectorData: desc.vectorData,
|
|
8195
|
+
pagePosition: desc.PgPs === 'PgPs.PgPC' ? 'centered' : desc.PgPs,
|
|
8196
|
+
left: (0, descriptor_1.parseUnits)(desc.Left),
|
|
8197
|
+
top: (0, descriptor_1.parseUnits)(desc['Top ']),
|
|
8198
|
+
scale: (0, descriptor_1.parsePercent)(desc['Scl ']),
|
|
8199
|
+
};
|
|
8200
|
+
if (desc.cropWhenPrinting !== undefined) {
|
|
8201
|
+
target.printStyle.cropWhenPrinting = desc.cropWhenPrinting;
|
|
8202
|
+
target.printStyle.cropRect = {
|
|
8203
|
+
top: desc.cropRectTop || 0,
|
|
8204
|
+
left: desc.cropRectLeft || 0,
|
|
8205
|
+
bottom: desc.cropRectBottom || 0,
|
|
8206
|
+
right: desc.cropRectRight || 0,
|
|
8207
|
+
};
|
|
8208
|
+
}
|
|
7859
8209
|
}, (writer, target) => {
|
|
7860
|
-
|
|
8210
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
8211
|
+
const style = target.printStyle;
|
|
8212
|
+
const desc = {
|
|
8213
|
+
Cptn: !!style.caption,
|
|
8214
|
+
Clbr: !!style.calibrationBars,
|
|
8215
|
+
RgsM: !!style.registrationMarks,
|
|
8216
|
+
CrnC: !!style.cornerCropMarks,
|
|
8217
|
+
CntC: !!style.centerCropMarks,
|
|
8218
|
+
Lbls: !!style.labels,
|
|
8219
|
+
Ngtv: !!style.negative,
|
|
8220
|
+
EmlD: !!style.emulsionDown,
|
|
8221
|
+
Intr: !!style.interpolate,
|
|
8222
|
+
Bckg: (0, descriptor_1.serializeColor)(style.backgroundColor || { r: 255, g: 255, b: 255 }),
|
|
8223
|
+
BrdT: (0, descriptor_1.unitsValue)(style.border || { units: 'Distance', value: 0 }, 'border'),
|
|
8224
|
+
'Bld ': (0, descriptor_1.unitsValue)(style.bleed || { units: 'Distance', value: 0 }, 'bleed'),
|
|
8225
|
+
Rslt: (0, descriptor_1.unitsValue)(style.resolution || { units: 'Pixels', value: 72 }, 'resolution'),
|
|
8226
|
+
vectorData: (_a = style.vectorData) !== null && _a !== void 0 ? _a : true,
|
|
8227
|
+
PgPs: (!style.pagePosition || style.pagePosition === 'centered') ? 'PgPs.PgPC' : style.pagePosition,
|
|
8228
|
+
Left: (0, descriptor_1.unitsValue)(style.left || { units: 'Distance', value: 0 }, 'left'),
|
|
8229
|
+
'Top ': (0, descriptor_1.unitsValue)(style.top || { units: 'Distance', value: 0 }, 'top'),
|
|
8230
|
+
'Scl ': (0, descriptor_1.unitsPercentF)((_b = style.scale) !== null && _b !== void 0 ? _b : 1),
|
|
8231
|
+
};
|
|
8232
|
+
if (style.cropWhenPrinting !== undefined || style.cropRect) {
|
|
8233
|
+
desc.cropWhenPrinting = !!style.cropWhenPrinting;
|
|
8234
|
+
desc.cropRectBottom = (_d = (_c = style.cropRect) === null || _c === void 0 ? void 0 : _c.bottom) !== null && _d !== void 0 ? _d : 0;
|
|
8235
|
+
desc.cropRectLeft = (_f = (_e = style.cropRect) === null || _e === void 0 ? void 0 : _e.left) !== null && _f !== void 0 ? _f : 0;
|
|
8236
|
+
desc.cropRectRight = (_h = (_g = style.cropRect) === null || _g === void 0 ? void 0 : _g.right) !== null && _h !== void 0 ? _h : 0;
|
|
8237
|
+
desc.cropRectTop = (_k = (_j = style.cropRect) === null || _j === void 0 ? void 0 : _j.top) !== null && _k !== void 0 ? _k : 0;
|
|
8238
|
+
}
|
|
8239
|
+
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'printOutputOptions', desc);
|
|
7861
8240
|
});
|
|
7862
8241
|
addHandler(1005, target => target.resolutionInfo !== undefined, (reader, target) => {
|
|
7863
8242
|
const horizontalResolution = (0, psdReader_1.readFixedPoint32)(reader);
|
|
@@ -7926,11 +8305,61 @@ addHandler(1045, target => target.alphaChannelNames !== undefined, (reader, targ
|
|
|
7926
8305
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
|
|
7927
8306
|
}
|
|
7928
8307
|
});
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
8308
|
+
const displayInfoKinds = ['selected', 'protected', 'spot'];
|
|
8309
|
+
const supportedColorSpaces = [0 /* ColorSpace.RGB */, 1 /* ColorSpace.HSB */, 2 /* ColorSpace.CMYK */, 7 /* ColorSpace.Lab */, 8 /* ColorSpace.Grayscale */];
|
|
8310
|
+
function readDisplayInfo(reader) {
|
|
8311
|
+
const info = { opacity: 0, kind: 'selected' };
|
|
8312
|
+
const colorSpace = reader.view.getUint16(reader.offset);
|
|
8313
|
+
if (supportedColorSpaces.indexOf(colorSpace) !== -1) {
|
|
8314
|
+
info.color = (0, psdReader_1.readColor)(reader);
|
|
8315
|
+
}
|
|
8316
|
+
else {
|
|
8317
|
+
// keep color in unknown color space as it is, so the channel info is not lost or misaligned
|
|
8318
|
+
(0, psdReader_1.skipBytes)(reader, 2);
|
|
8319
|
+
info.rawColor = { colorSpace, values: [(0, psdReader_1.readUint16)(reader), (0, psdReader_1.readUint16)(reader), (0, psdReader_1.readUint16)(reader), (0, psdReader_1.readUint16)(reader)] };
|
|
8320
|
+
}
|
|
8321
|
+
info.opacity = (0, psdReader_1.readUint16)(reader) / 100;
|
|
8322
|
+
const kind = displayInfoKinds[(0, psdReader_1.readUint8)(reader)];
|
|
8323
|
+
if (!kind)
|
|
8324
|
+
throw new Error('Invalid display info kind');
|
|
8325
|
+
info.kind = kind;
|
|
8326
|
+
return info;
|
|
8327
|
+
}
|
|
8328
|
+
addHandler(1007, // Display info (obsolete, replaced by 1077), written back as 1077
|
|
8329
|
+
() => false, (reader, target, left) => {
|
|
8330
|
+
const info = [];
|
|
8331
|
+
while (left() >= 14) {
|
|
8332
|
+
info.push(readDisplayInfo(reader));
|
|
8333
|
+
(0, psdReader_1.skipBytes)(reader, 1); // padding
|
|
8334
|
+
}
|
|
8335
|
+
// 1077 resource has more precise data and is used if present
|
|
8336
|
+
if (!target.alphaChannelDisplayInfo)
|
|
8337
|
+
target.alphaChannelDisplayInfo = info;
|
|
8338
|
+
}, () => { });
|
|
8339
|
+
addHandler(1077, // Display info (alpha and spot channels)
|
|
8340
|
+
// Display info (alpha and spot channels)
|
|
8341
|
+
target => target.alphaChannelDisplayInfo !== undefined, (reader, target, left) => {
|
|
8342
|
+
const version = (0, psdReader_1.readUint32)(reader);
|
|
8343
|
+
if (version !== 1)
|
|
8344
|
+
throw new Error(`Invalid display info version: ${version}`);
|
|
8345
|
+
target.alphaChannelDisplayInfo = [];
|
|
8346
|
+
while (left() >= 13) {
|
|
8347
|
+
target.alphaChannelDisplayInfo.push(readDisplayInfo(reader));
|
|
8348
|
+
}
|
|
7932
8349
|
}, (writer, target) => {
|
|
7933
|
-
(0, psdWriter_1.
|
|
8350
|
+
(0, psdWriter_1.writeUint32)(writer, 1); // version
|
|
8351
|
+
for (const info of target.alphaChannelDisplayInfo) {
|
|
8352
|
+
if (!info.color && info.rawColor) {
|
|
8353
|
+
(0, psdWriter_1.writeUint16)(writer, info.rawColor.colorSpace);
|
|
8354
|
+
for (let i = 0; i < 4; i++)
|
|
8355
|
+
(0, psdWriter_1.writeUint16)(writer, info.rawColor.values[i] | 0);
|
|
8356
|
+
}
|
|
8357
|
+
else {
|
|
8358
|
+
(0, psdWriter_1.writeColor)(writer, info.color || { r: 255, g: 0, b: 0 });
|
|
8359
|
+
}
|
|
8360
|
+
(0, psdWriter_1.writeUint16)(writer, Math.round((0, helpers_1.clamp)(info.opacity, 0, 1) * 100));
|
|
8361
|
+
(0, psdWriter_1.writeUint8)(writer, Math.max(0, displayInfoKinds.indexOf(info.kind)));
|
|
8362
|
+
}
|
|
7934
8363
|
});
|
|
7935
8364
|
addHandler(1053, target => target.alphaIdentifiers !== undefined, (reader, target, left) => {
|
|
7936
8365
|
target.alphaIdentifiers = [];
|
|
@@ -7983,30 +8412,101 @@ target => target.url !== undefined, (reader, target, left) => {
|
|
|
7983
8412
|
}, (writer, target) => {
|
|
7984
8413
|
(0, psdWriter_1.writeAsciiString)(writer, target.url);
|
|
7985
8414
|
});
|
|
7986
|
-
|
|
7987
|
-
// Print flags
|
|
7988
|
-
target => target.
|
|
7989
|
-
|
|
7990
|
-
|
|
8415
|
+
addHandler(10000, // Print flags information
|
|
8416
|
+
// Print flags information
|
|
8417
|
+
target => target.printFlagsInfo !== undefined, (reader, target) => {
|
|
8418
|
+
const version = (0, psdReader_1.readUint16)(reader);
|
|
8419
|
+
if (version !== 1)
|
|
8420
|
+
throw new Error(`Invalid print flags information version: ${version}`);
|
|
8421
|
+
const centerCropMarks = !!(0, psdReader_1.readUint8)(reader);
|
|
8422
|
+
(0, psdReader_1.skipBytes)(reader, 1);
|
|
8423
|
+
const bleedWidth = (0, psdReader_1.readUint32)(reader);
|
|
8424
|
+
const bleedWidthScale = (0, psdReader_1.readUint16)(reader);
|
|
8425
|
+
target.printFlagsInfo = { centerCropMarks, bleedWidth, bleedWidthScale };
|
|
7991
8426
|
}, (writer, target) => {
|
|
7992
|
-
|
|
8427
|
+
const info = target.printFlagsInfo;
|
|
8428
|
+
(0, psdWriter_1.writeUint16)(writer, 1); // version
|
|
8429
|
+
(0, psdWriter_1.writeUint8)(writer, info.centerCropMarks ? 1 : 0);
|
|
8430
|
+
(0, psdWriter_1.writeUint8)(writer, 0);
|
|
8431
|
+
(0, psdWriter_1.writeUint32)(writer, info.bleedWidth | 0);
|
|
8432
|
+
(0, psdWriter_1.writeUint16)(writer, info.bleedWidthScale | 0);
|
|
7993
8433
|
});
|
|
7994
|
-
|
|
7995
|
-
//
|
|
7996
|
-
target => target.
|
|
7997
|
-
|
|
7998
|
-
target._ir1013 = (0, psdReader_1.readBytes)(reader, left());
|
|
8434
|
+
addHandler(1046, // Indexed color table count
|
|
8435
|
+
// Indexed color table count
|
|
8436
|
+
target => target.indexedColorCount !== undefined, (reader, target) => {
|
|
8437
|
+
target.indexedColorCount = (0, psdReader_1.readUint16)(reader);
|
|
7999
8438
|
}, (writer, target) => {
|
|
8000
|
-
(0, psdWriter_1.
|
|
8439
|
+
(0, psdWriter_1.writeUint16)(writer, target.indexedColorCount);
|
|
8001
8440
|
});
|
|
8002
|
-
|
|
8003
|
-
//
|
|
8004
|
-
target => target.
|
|
8005
|
-
|
|
8006
|
-
target._ir1016 = (0, psdReader_1.readBytes)(reader, left());
|
|
8441
|
+
addHandler(1047, // Transparency index
|
|
8442
|
+
// Transparency index
|
|
8443
|
+
target => target.transparencyIndex !== undefined, (reader, target) => {
|
|
8444
|
+
target.transparencyIndex = (0, psdReader_1.readUint16)(reader);
|
|
8007
8445
|
}, (writer, target) => {
|
|
8008
|
-
(0, psdWriter_1.
|
|
8446
|
+
(0, psdWriter_1.writeUint16)(writer, target.transparencyIndex);
|
|
8009
8447
|
});
|
|
8448
|
+
const halftoneFrequencyUnits = ['lines/inch', 'lines/cm']; // 1, 2
|
|
8449
|
+
const halftoneShapes = ['round', 'ellipse', 'line', 'square', 'cross', undefined, 'diamond']; // 0 - 6
|
|
8450
|
+
function readHalftoneScreens(reader, left) {
|
|
8451
|
+
const screens = [];
|
|
8452
|
+
while (left() >= 18) {
|
|
8453
|
+
const frequency = (0, psdReader_1.readFixedPoint32)(reader);
|
|
8454
|
+
const frequencyUnits = halftoneFrequencyUnits[(0, psdReader_1.readUint16)(reader) - 1];
|
|
8455
|
+
if (!frequencyUnits)
|
|
8456
|
+
throw new Error('Invalid halftone screen frequency units');
|
|
8457
|
+
const angle = (0, psdReader_1.readFixedPoint32)(reader);
|
|
8458
|
+
const shape = halftoneShapes[(0, psdReader_1.readInt16)(reader)];
|
|
8459
|
+
if (!shape)
|
|
8460
|
+
throw new Error('Invalid halftone screen shape');
|
|
8461
|
+
(0, psdReader_1.skipBytes)(reader, 4);
|
|
8462
|
+
const accurateScreens = !!(0, psdReader_1.readUint8)(reader);
|
|
8463
|
+
const printerDefaultScreens = !!(0, psdReader_1.readUint8)(reader);
|
|
8464
|
+
screens.push({ frequency, frequencyUnits, angle, shape, accurateScreens, printerDefaultScreens });
|
|
8465
|
+
}
|
|
8466
|
+
return screens;
|
|
8467
|
+
}
|
|
8468
|
+
function writeHalftoneScreens(writer, screens) {
|
|
8469
|
+
for (const screen of screens) {
|
|
8470
|
+
(0, psdWriter_1.writeFixedPoint32)(writer, screen.frequency);
|
|
8471
|
+
(0, psdWriter_1.writeUint16)(writer, Math.max(0, halftoneFrequencyUnits.indexOf(screen.frequencyUnits)) + 1);
|
|
8472
|
+
(0, psdWriter_1.writeFixedPoint32)(writer, screen.angle);
|
|
8473
|
+
(0, psdWriter_1.writeInt16)(writer, Math.max(0, halftoneShapes.indexOf(screen.shape)));
|
|
8474
|
+
(0, psdWriter_1.writeZeros)(writer, 4);
|
|
8475
|
+
(0, psdWriter_1.writeUint8)(writer, screen.accurateScreens ? 1 : 0);
|
|
8476
|
+
(0, psdWriter_1.writeUint8)(writer, screen.printerDefaultScreens ? 1 : 0);
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
addHandler(1012, // Grayscale and multichannel halftoning information
|
|
8480
|
+
// Grayscale and multichannel halftoning information
|
|
8481
|
+
target => target.grayscaleHalftoneScreens !== undefined, (reader, target, left) => target.grayscaleHalftoneScreens = readHalftoneScreens(reader, left), (writer, target) => writeHalftoneScreens(writer, target.grayscaleHalftoneScreens));
|
|
8482
|
+
addHandler(1013, // Color halftoning information
|
|
8483
|
+
// Color halftoning information
|
|
8484
|
+
target => target.colorHalftoneScreens !== undefined, (reader, target, left) => target.colorHalftoneScreens = readHalftoneScreens(reader, left), (writer, target) => writeHalftoneScreens(writer, target.colorHalftoneScreens));
|
|
8485
|
+
function readTransferFunctions(reader, left) {
|
|
8486
|
+
const functions = [];
|
|
8487
|
+
while (left() >= 28) {
|
|
8488
|
+
const curve = [];
|
|
8489
|
+
for (let i = 0; i < 13; i++)
|
|
8490
|
+
curve.push((0, psdReader_1.readInt16)(reader));
|
|
8491
|
+
const override = !!(0, psdReader_1.readUint16)(reader);
|
|
8492
|
+
functions.push({ curve, override });
|
|
8493
|
+
}
|
|
8494
|
+
return functions;
|
|
8495
|
+
}
|
|
8496
|
+
function writeTransferFunctions(writer, functions) {
|
|
8497
|
+
var _a;
|
|
8498
|
+
for (const f of functions) {
|
|
8499
|
+
for (let i = 0; i < 13; i++)
|
|
8500
|
+
(0, psdWriter_1.writeInt16)(writer, (_a = f.curve[i]) !== null && _a !== void 0 ? _a : -1);
|
|
8501
|
+
(0, psdWriter_1.writeUint16)(writer, f.override ? 1 : 0);
|
|
8502
|
+
}
|
|
8503
|
+
}
|
|
8504
|
+
addHandler(1015, // Grayscale and multichannel transfer function
|
|
8505
|
+
// Grayscale and multichannel transfer function
|
|
8506
|
+
target => target.grayscaleTransferFunctions !== undefined, (reader, target, left) => target.grayscaleTransferFunctions = readTransferFunctions(reader, left), (writer, target) => writeTransferFunctions(writer, target.grayscaleTransferFunctions));
|
|
8507
|
+
addHandler(1016, // Color transfer functions
|
|
8508
|
+
// Color transfer functions
|
|
8509
|
+
target => target.colorTransferFunctions !== undefined, (reader, target, left) => target.colorTransferFunctions = readTransferFunctions(reader, left), (writer, target) => writeTransferFunctions(writer, target.colorTransferFunctions));
|
|
8010
8510
|
addHandler(1080, // Count Information
|
|
8011
8511
|
// Count Information
|
|
8012
8512
|
target => target.countInformation !== undefined, (reader, target) => {
|
|
@@ -8069,22 +8569,27 @@ addHandler(1069, target => target.layerSelectionIds !== undefined, (reader, targ
|
|
|
8069
8569
|
}
|
|
8070
8570
|
});
|
|
8071
8571
|
addHandler(1032, target => target.gridAndGuidesInformation !== undefined, (reader, target) => {
|
|
8572
|
+
var _a;
|
|
8072
8573
|
const version = (0, psdReader_1.readUint32)(reader);
|
|
8073
8574
|
const horizontal = (0, psdReader_1.readUint32)(reader);
|
|
8074
8575
|
const vertical = (0, psdReader_1.readUint32)(reader);
|
|
8075
8576
|
const count = (0, psdReader_1.readUint32)(reader);
|
|
8076
8577
|
if (version !== 1)
|
|
8077
8578
|
throw new Error(`Invalid 1032 resource version: ${version}`);
|
|
8078
|
-
target.gridAndGuidesInformation
|
|
8079
|
-
|
|
8080
|
-
guides: [],
|
|
8081
|
-
};
|
|
8579
|
+
const previous = (_a = target.gridAndGuidesInformation) === null || _a === void 0 ? void 0 : _a.guides; // in case guides were already read from 1092
|
|
8580
|
+
const guides = [];
|
|
8082
8581
|
for (let i = 0; i < count; i++) {
|
|
8083
|
-
|
|
8582
|
+
const guide = {
|
|
8084
8583
|
location: (0, psdReader_1.readInt32)(reader) / 32,
|
|
8085
8584
|
direction: (0, psdReader_1.readUint8)(reader) ? 'horizontal' : 'vertical'
|
|
8086
|
-
}
|
|
8585
|
+
};
|
|
8586
|
+
if ((previous === null || previous === void 0 ? void 0 : previous.length) === count && previous[i].color)
|
|
8587
|
+
guide.color = previous[i].color;
|
|
8588
|
+
if ((previous === null || previous === void 0 ? void 0 : previous.length) === count && previous[i].id)
|
|
8589
|
+
guide.id = previous[i].id;
|
|
8590
|
+
guides.push(guide);
|
|
8087
8591
|
}
|
|
8592
|
+
target.gridAndGuidesInformation = { grid: { horizontal, vertical }, guides };
|
|
8088
8593
|
}, (writer, target) => {
|
|
8089
8594
|
const info = target.gridAndGuidesInformation;
|
|
8090
8595
|
const grid = info.grid || { horizontal: 18 * 32, vertical: 18 * 32 };
|
|
@@ -8098,6 +8603,76 @@ addHandler(1032, target => target.gridAndGuidesInformation !== undefined, (reade
|
|
|
8098
8603
|
(0, psdWriter_1.writeUint8)(writer, g.direction === 'horizontal' ? 1 : 0);
|
|
8099
8604
|
}
|
|
8100
8605
|
});
|
|
8606
|
+
const defaultGuideColor = { r: 74, g: 255, b: 255 }; // Photoshop default (cyan)
|
|
8607
|
+
addHandler(1092, // Grid and guides information with guide colors (same as 1032 with color of each guide)
|
|
8608
|
+
// Grid and guides information with guide colors (same as 1032 with color of each guide)
|
|
8609
|
+
target => target.gridAndGuidesInformation !== undefined, (reader, target) => {
|
|
8610
|
+
var _a;
|
|
8611
|
+
const version = (0, psdReader_1.readUint32)(reader);
|
|
8612
|
+
if (version !== 2)
|
|
8613
|
+
throw new Error(`Invalid 1092 resource version: ${version}`);
|
|
8614
|
+
const horizontal = (0, psdReader_1.readUint32)(reader);
|
|
8615
|
+
const vertical = (0, psdReader_1.readUint32)(reader);
|
|
8616
|
+
const count = (0, psdReader_1.readUint32)(reader);
|
|
8617
|
+
const guides = [];
|
|
8618
|
+
for (let i = 0; i < count; i++) {
|
|
8619
|
+
const location = (0, psdReader_1.readInt32)(reader) / 32;
|
|
8620
|
+
const direction = (0, psdReader_1.readUint8)(reader) ? 'horizontal' : 'vertical';
|
|
8621
|
+
(0, psdReader_1.skipBytes)(reader, 1);
|
|
8622
|
+
const color = { r: (0, psdReader_1.readUint8)(reader), g: (0, psdReader_1.readUint8)(reader), b: (0, psdReader_1.readUint8)(reader) };
|
|
8623
|
+
guides.push({ location, direction, color });
|
|
8624
|
+
}
|
|
8625
|
+
const existing = (_a = target.gridAndGuidesInformation) === null || _a === void 0 ? void 0 : _a.guides;
|
|
8626
|
+
if (existing && existing.length === count) {
|
|
8627
|
+
existing.forEach((guide, i) => guide.color = guides[i].color);
|
|
8628
|
+
}
|
|
8629
|
+
else {
|
|
8630
|
+
target.gridAndGuidesInformation = { grid: { horizontal, vertical }, guides };
|
|
8631
|
+
}
|
|
8632
|
+
}, (writer, target) => {
|
|
8633
|
+
const info = target.gridAndGuidesInformation;
|
|
8634
|
+
const grid = info.grid || { horizontal: 18 * 32, vertical: 18 * 32 };
|
|
8635
|
+
const guides = info.guides || [];
|
|
8636
|
+
(0, psdWriter_1.writeUint32)(writer, 2); // version
|
|
8637
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round(grid.horizontal));
|
|
8638
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round(grid.vertical));
|
|
8639
|
+
(0, psdWriter_1.writeUint32)(writer, guides.length);
|
|
8640
|
+
for (const g of guides) {
|
|
8641
|
+
const color = g.color || defaultGuideColor;
|
|
8642
|
+
(0, psdWriter_1.writeInt32)(writer, Math.round(g.location * 32));
|
|
8643
|
+
(0, psdWriter_1.writeUint8)(writer, g.direction === 'horizontal' ? 1 : 0);
|
|
8644
|
+
(0, psdWriter_1.writeUint8)(writer, 0);
|
|
8645
|
+
(0, psdWriter_1.writeUint8)(writer, Math.round(color.r));
|
|
8646
|
+
(0, psdWriter_1.writeUint8)(writer, Math.round(color.g));
|
|
8647
|
+
(0, psdWriter_1.writeUint8)(writer, Math.round(color.b));
|
|
8648
|
+
}
|
|
8649
|
+
});
|
|
8650
|
+
const emptyGuid = '00000000-0000-0000-0000-000000000000';
|
|
8651
|
+
addHandler(1097, // Guide ids
|
|
8652
|
+
// Guide ids
|
|
8653
|
+
target => !!target.gridAndGuidesInformation && (target.gridAndGuidesInformation.guides || []).every(g => g.id), (reader, target) => {
|
|
8654
|
+
var _a;
|
|
8655
|
+
const count = (0, psdReader_1.readUint32)(reader);
|
|
8656
|
+
const ids = [];
|
|
8657
|
+
for (let i = 0; i < count; i++) {
|
|
8658
|
+
ids.push((0, psdReader_1.readAsciiString)(reader, (0, psdReader_1.readUint32)(reader)));
|
|
8659
|
+
(0, psdReader_1.readUint32)(reader); // unknown, always 0
|
|
8660
|
+
(0, psdReader_1.readAsciiString)(reader, (0, psdReader_1.readUint32)(reader)); // unknown, always empty guid
|
|
8661
|
+
}
|
|
8662
|
+
const guides = (_a = target.gridAndGuidesInformation) === null || _a === void 0 ? void 0 : _a.guides;
|
|
8663
|
+
if (guides && guides.length === count)
|
|
8664
|
+
guides.forEach((guide, i) => guide.id = ids[i]);
|
|
8665
|
+
}, (writer, target) => {
|
|
8666
|
+
const guides = target.gridAndGuidesInformation.guides || [];
|
|
8667
|
+
(0, psdWriter_1.writeUint32)(writer, guides.length);
|
|
8668
|
+
for (const g of guides) {
|
|
8669
|
+
(0, psdWriter_1.writeUint32)(writer, g.id.length);
|
|
8670
|
+
(0, psdWriter_1.writeAsciiString)(writer, g.id);
|
|
8671
|
+
(0, psdWriter_1.writeUint32)(writer, 0);
|
|
8672
|
+
(0, psdWriter_1.writeUint32)(writer, emptyGuid.length);
|
|
8673
|
+
(0, psdWriter_1.writeAsciiString)(writer, emptyGuid);
|
|
8674
|
+
}
|
|
8675
|
+
});
|
|
8101
8676
|
addHandler(1065, // Layer Comps
|
|
8102
8677
|
// Layer Comps
|
|
8103
8678
|
target => target.layerComps !== undefined, (reader, target) => {
|
|
@@ -8478,27 +9053,78 @@ addHandler(1041, target => target.iccUntaggedProfile !== undefined, (reader, tar
|
|
|
8478
9053
|
}, (writer, target) => {
|
|
8479
9054
|
(0, psdWriter_1.writeUint8)(writer, target.iccUntaggedProfile ? 1 : 0);
|
|
8480
9055
|
});
|
|
8481
|
-
|
|
9056
|
+
addHandler(1039, // ICC Profile
|
|
8482
9057
|
// ICC Profile
|
|
8483
|
-
target => target.
|
|
8484
|
-
|
|
8485
|
-
LOG_MOCK_HANDLERS && console.log('image resource 1039', left());
|
|
8486
|
-
target._ir1039 = (0, psdReader_1.readBytes)(reader, left());
|
|
9058
|
+
target => target.iccProfile !== undefined, (reader, target, left) => {
|
|
9059
|
+
target.iccProfile = (0, psdReader_1.readBytes)(reader, left());
|
|
8487
9060
|
}, (writer, target) => {
|
|
8488
|
-
(0, psdWriter_1.writeBytes)(writer, target.
|
|
9061
|
+
(0, psdWriter_1.writeBytes)(writer, target.iccProfile);
|
|
8489
9062
|
});
|
|
8490
9063
|
addHandler(1044, target => target.idsSeedNumber !== undefined, (reader, target) => target.idsSeedNumber = (0, psdReader_1.readUint32)(reader), (writer, target) => (0, psdWriter_1.writeUint32)(writer, target.idsSeedNumber));
|
|
9064
|
+
addHandler(1038, // Color samplers (Photoshop 5.0, replaced by 1073 in CS3)
|
|
9065
|
+
// Color samplers (Photoshop 5.0, replaced by 1073 in CS3)
|
|
9066
|
+
target => target.colorSamplers !== undefined, (reader, target, left) => {
|
|
9067
|
+
const version = (0, psdReader_1.readUint32)(reader);
|
|
9068
|
+
if (version !== 1)
|
|
9069
|
+
throw new Error(`Invalid color samplers version: ${version}`);
|
|
9070
|
+
const count = (0, psdReader_1.readUint32)(reader);
|
|
9071
|
+
target.colorSamplers = [];
|
|
9072
|
+
for (let i = 0; i < count && left() >= 10; i++) {
|
|
9073
|
+
// vertical and horizontal position in 1/16 pixel (inferred from sample files, the specification describes
|
|
9074
|
+
// these values as horizontal and vertical fixed point numbers)
|
|
9075
|
+
const y = (0, psdReader_1.readInt32)(reader) / 16;
|
|
9076
|
+
const x = (0, psdReader_1.readInt32)(reader) / 16;
|
|
9077
|
+
const colorSpace = (0, psdReader_1.readInt16)(reader);
|
|
9078
|
+
target.colorSamplers.push({ x, y, colorSpace });
|
|
9079
|
+
}
|
|
9080
|
+
}, (writer, target) => {
|
|
9081
|
+
(0, psdWriter_1.writeUint32)(writer, 1); // version
|
|
9082
|
+
(0, psdWriter_1.writeUint32)(writer, target.colorSamplers.length);
|
|
9083
|
+
for (const sampler of target.colorSamplers) {
|
|
9084
|
+
(0, psdWriter_1.writeInt32)(writer, Math.round(sampler.y * 16));
|
|
9085
|
+
(0, psdWriter_1.writeInt32)(writer, Math.round(sampler.x * 16));
|
|
9086
|
+
(0, psdWriter_1.writeInt16)(writer, sampler.colorSpace);
|
|
9087
|
+
}
|
|
9088
|
+
});
|
|
9089
|
+
addHandler(1042, // Effects visible (only present when effects are hidden)
|
|
9090
|
+
// Effects visible (only present when effects are hidden)
|
|
9091
|
+
target => target.effectsVisible !== undefined, (reader, target) => {
|
|
9092
|
+
target.effectsVisible = !!(0, psdReader_1.readUint8)(reader);
|
|
9093
|
+
}, (writer, target) => {
|
|
9094
|
+
(0, psdWriter_1.writeUint8)(writer, target.effectsVisible ? 1 : 0);
|
|
9095
|
+
});
|
|
8491
9096
|
addHandler(1036, target => target.thumbnail !== undefined || target.thumbnailRaw !== undefined, (reader, target, left) => {
|
|
8492
9097
|
const format = (0, psdReader_1.readUint32)(reader); // 1 = kJpegRGB, 0 = kRawRGB
|
|
8493
9098
|
const width = (0, psdReader_1.readUint32)(reader);
|
|
8494
9099
|
const height = (0, psdReader_1.readUint32)(reader);
|
|
8495
|
-
(0, psdReader_1.readUint32)(reader); // widthBytes = (width * bits_per_pixel + 31) / 32 * 4.
|
|
9100
|
+
const widthBytes = (0, psdReader_1.readUint32)(reader); // widthBytes = (width * bits_per_pixel + 31) / 32 * 4.
|
|
8496
9101
|
(0, psdReader_1.readUint32)(reader); // totalSize = widthBytes * height * planes
|
|
8497
9102
|
(0, psdReader_1.readUint32)(reader); // sizeAfterCompression
|
|
8498
9103
|
const bitsPerPixel = (0, psdReader_1.readUint16)(reader); // 24
|
|
8499
|
-
|
|
8500
|
-
if (format
|
|
8501
|
-
|
|
9104
|
+
(0, psdReader_1.readUint16)(reader); // planes, should be 1 (some applications write 3)
|
|
9105
|
+
if (format === 0 && bitsPerPixel === 24 && widthBytes >= width * 3 && widthBytes * height <= left()) {
|
|
9106
|
+
// raw RGB data, rows are padded to 4 bytes
|
|
9107
|
+
if (reader.useRawThumbnail) {
|
|
9108
|
+
reader.logMissingFeatures && reader.log('Raw thumbnail data is not supported with useRawThumbnail option');
|
|
9109
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9110
|
+
return;
|
|
9111
|
+
}
|
|
9112
|
+
const data = (0, psdReader_1.readBytes)(reader, widthBytes * height);
|
|
9113
|
+
const imageData = (0, helpers_1.createImageData)(width, height);
|
|
9114
|
+
for (let y = 0, dst = 0; y < height; y++) {
|
|
9115
|
+
for (let x = 0, src = y * widthBytes; x < width; x++, src += 3, dst += 4) {
|
|
9116
|
+
imageData.data[dst + 0] = data[src + 0];
|
|
9117
|
+
imageData.data[dst + 1] = data[src + 1];
|
|
9118
|
+
imageData.data[dst + 2] = data[src + 2];
|
|
9119
|
+
imageData.data[dst + 3] = 255;
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9122
|
+
target.thumbnail = (0, helpers_1.imageDataToCanvas)(imageData);
|
|
9123
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9124
|
+
return;
|
|
9125
|
+
}
|
|
9126
|
+
if (format !== 1 || bitsPerPixel !== 24) {
|
|
9127
|
+
reader.logMissingFeatures && reader.log(`Invalid thumbnail data (format: ${format}, bitsPerPixel: ${bitsPerPixel})`);
|
|
8502
9128
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
8503
9129
|
return;
|
|
8504
9130
|
}
|
|
@@ -8565,13 +9191,12 @@ addHandler(1057, target => target.versionInfo !== undefined, (reader, target, le
|
|
|
8565
9191
|
(0, psdWriter_1.writeUnicodeString)(writer, versionInfo.readerName);
|
|
8566
9192
|
(0, psdWriter_1.writeUint32)(writer, versionInfo.fileVersion);
|
|
8567
9193
|
});
|
|
8568
|
-
|
|
8569
|
-
// EXIF data 1
|
|
8570
|
-
target => target.
|
|
8571
|
-
|
|
8572
|
-
target._ir1058 = (0, psdReader_1.readBytes)(reader, left());
|
|
9194
|
+
addHandler(1058, // EXIF data 1
|
|
9195
|
+
// EXIF data 1
|
|
9196
|
+
target => target.exifData !== undefined, (reader, target, left) => {
|
|
9197
|
+
target.exifData = (0, psdReader_1.readBytes)(reader, left());
|
|
8573
9198
|
}, (writer, target) => {
|
|
8574
|
-
(0, psdWriter_1.writeBytes)(writer, target.
|
|
9199
|
+
(0, psdWriter_1.writeBytes)(writer, target.exifData);
|
|
8575
9200
|
});
|
|
8576
9201
|
addHandler(7000, target => target.imageReadyVariables !== undefined, (reader, target, left) => {
|
|
8577
9202
|
target.imageReadyVariables = readUtf8String(reader, left());
|
|
@@ -8590,22 +9215,101 @@ addHandler(1088, target => target.pathSelectionState !== undefined, (reader, tar
|
|
|
8590
9215
|
const desc = { 'null': (0, descriptor_1.pathSelectionStateToReference)(target.pathSelectionState) };
|
|
8591
9216
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
8592
9217
|
});
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
9218
|
+
addHandler(1025, // Work path
|
|
9219
|
+
// Work path
|
|
9220
|
+
target => target.workPath !== undefined, (reader, target, left, { width, height }) => {
|
|
9221
|
+
target.workPath = { paths: [] };
|
|
9222
|
+
(0, additionalInfo_1.readVectorMask)(reader, target.workPath, width, height, left());
|
|
9223
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9224
|
+
}, (writer, target, _index, { width, height }) => {
|
|
9225
|
+
(0, additionalInfo_1.writeVectorMask)(writer, target.workPath, width, height);
|
|
9226
|
+
});
|
|
9227
|
+
const MAX_SAVED_PATHS = 999; // ids 2000-2998
|
|
9228
|
+
addHandler(2000, // Saved paths (one resource for each path, named after the path)
|
|
9229
|
+
// Saved paths (one resource for each path, named after the path)
|
|
9230
|
+
target => target.savedPaths ? Math.min(target.savedPaths.length, MAX_SAVED_PATHS) : 0, (reader, target, left, { signature, id, name, width, height }) => {
|
|
9231
|
+
var _a, _b;
|
|
9232
|
+
if (signature !== '8BIM') { // ImageReady ('MeSa') resources use the same ids for other data
|
|
9233
|
+
reader.logMissingFeatures && reader.log(`Unhandled image resource: ${signature} ${id}`);
|
|
9234
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9235
|
+
return;
|
|
9236
|
+
}
|
|
9237
|
+
const savedPaths = (_a = target.savedPaths) !== null && _a !== void 0 ? _a : (target.savedPaths = []);
|
|
9238
|
+
const path = { name: decodeEncodedString(reader, name), paths: [] };
|
|
9239
|
+
(0, additionalInfo_1.readVectorMask)(reader, path, width, height, left());
|
|
9240
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9241
|
+
const keyDescriptorList = (_b = target.savedPathsOrigination) === null || _b === void 0 ? void 0 : _b[savedPaths.length];
|
|
9242
|
+
if (keyDescriptorList)
|
|
9243
|
+
path.vectorOrigination = { keyDescriptorList };
|
|
9244
|
+
savedPaths.push(path);
|
|
9245
|
+
}, (writer, target, index, { width, height }) => {
|
|
9246
|
+
(0, additionalInfo_1.writeVectorMask)(writer, target.savedPaths[index], width, height);
|
|
9247
|
+
}, { keyCount: MAX_SAVED_PATHS, name: (target, index) => toShortAsciiString(target.savedPaths[index].name) });
|
|
9248
|
+
addHandler(3000, // Origin path info (origination data of saved paths)
|
|
9249
|
+
// Origin path info (origination data of saved paths)
|
|
9250
|
+
target => { var _a; return !!((_a = target.savedPaths) === null || _a === void 0 ? void 0 : _a.some(path => path.vectorOrigination)); }, (reader, target, left) => {
|
|
9251
|
+
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
9252
|
+
desc.keyRootDescriptorList.forEach((item, i) => {
|
|
9253
|
+
var _a, _b;
|
|
9254
|
+
const keyDescriptorList = (0, additionalInfo_1.parseKeyDescriptorList)(item);
|
|
9255
|
+
if (!keyDescriptorList.length)
|
|
9256
|
+
return; // written for paths without origination data
|
|
9257
|
+
const path = (_a = target.savedPaths) === null || _a === void 0 ? void 0 : _a[i];
|
|
9258
|
+
if (path) {
|
|
9259
|
+
path.vectorOrigination = { keyDescriptorList };
|
|
9260
|
+
}
|
|
9261
|
+
else { // saved paths are stored after this resource
|
|
9262
|
+
((_b = target.savedPathsOrigination) !== null && _b !== void 0 ? _b : (target.savedPathsOrigination = []))[i] = keyDescriptorList;
|
|
9263
|
+
}
|
|
9264
|
+
});
|
|
9265
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9266
|
+
}, (writer, target) => {
|
|
9267
|
+
const desc = {
|
|
9268
|
+
keyRootDescriptorList: target.savedPaths.slice(0, MAX_SAVED_PATHS)
|
|
9269
|
+
.map(path => { var _a, _b; return (0, additionalInfo_1.serializeKeyDescriptorList)((_b = (_a = path.vectorOrigination) === null || _a === void 0 ? void 0 : _a.keyDescriptorList) !== null && _b !== void 0 ? _b : []); }),
|
|
9270
|
+
};
|
|
9271
|
+
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
9272
|
+
}, { name: () => 'OriginDataIRB' });
|
|
9273
|
+
addHandler(2999, // Clipping path
|
|
9274
|
+
// Clipping path
|
|
9275
|
+
target => target.clippingPath !== undefined, (reader, target, left) => {
|
|
9276
|
+
const name = readEncodedString(reader);
|
|
9277
|
+
const flatness = (0, psdReader_1.readFixedPoint32)(reader);
|
|
9278
|
+
(0, psdReader_1.skipBytes)(reader, left()); // fill rule (ignored by Photoshop)
|
|
9279
|
+
target.clippingPath = { name, flatness };
|
|
8596
9280
|
}, (writer, target) => {
|
|
8597
|
-
(
|
|
9281
|
+
writeEncodedString(writer, target.clippingPath.name);
|
|
9282
|
+
(0, psdWriter_1.writeFixedPoint32)(writer, target.clippingPath.flatness);
|
|
9283
|
+
(0, psdWriter_1.writeUint16)(writer, 1); // fill rule (ignored by Photoshop)
|
|
8598
9284
|
});
|
|
8599
9285
|
const FrmD = (0, helpers_1.createEnum)('FrmD', 'auto', {
|
|
8600
9286
|
auto: 'Auto',
|
|
8601
9287
|
none: 'None',
|
|
8602
9288
|
dispose: 'Disp',
|
|
8603
9289
|
});
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
9290
|
+
// plug-in resources are written with consecutive ids starting at 4000, in the same order as Photoshop writes them
|
|
9291
|
+
function pluginResourceKeys(target) {
|
|
9292
|
+
const keys = [];
|
|
9293
|
+
if (target.outputSettings !== undefined)
|
|
9294
|
+
keys.push('mset');
|
|
9295
|
+
if (target.animations !== undefined)
|
|
9296
|
+
keys.push('mani', 'mfri');
|
|
9297
|
+
return keys;
|
|
9298
|
+
}
|
|
9299
|
+
addHandler(4000, // Plug-In resource(s), identified by key stored in the data (ids 4000-4999)
|
|
9300
|
+
// Plug-In resource(s), identified by key stored in the data (ids 4000-4999)
|
|
9301
|
+
target => pluginResourceKeys(target).length, (reader, target, left) => {
|
|
8607
9302
|
const key = (0, psdReader_1.readSignature)(reader);
|
|
8608
|
-
if (key === '
|
|
9303
|
+
if (key === 'mset') {
|
|
9304
|
+
// Save for Web output settings
|
|
9305
|
+
target.outputSettings = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
9306
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9307
|
+
}
|
|
9308
|
+
else if (key === 'mfri') {
|
|
9309
|
+
// frame count, active frame and animation count, same data as in animations (mani)
|
|
9310
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
9311
|
+
}
|
|
9312
|
+
else if (key === 'mani') {
|
|
8609
9313
|
(0, psdReader_1.checkSignature)(reader, 'IRFR');
|
|
8610
9314
|
(0, psdReader_1.readSection)(reader, 1, left => {
|
|
8611
9315
|
while (left() > 0) {
|
|
@@ -8631,6 +9335,7 @@ target => target.animations !== undefined, (reader, target, left) => {
|
|
|
8631
9335
|
};
|
|
8632
9336
|
// console.log('#4000 AnDs', require('util').inspect(desc, false, 99, true));
|
|
8633
9337
|
// console.log('#4000 AnDs:result', require('util').inspect(target.animations, false, 99, true));
|
|
9338
|
+
(0, psdReader_1.skipBytes)(reader, left()); // padding
|
|
8634
9339
|
}
|
|
8635
9340
|
else if (key === 'Roll') {
|
|
8636
9341
|
const bytes = (0, psdReader_1.readBytes)(reader, left());
|
|
@@ -8638,20 +9343,39 @@ target => target.animations !== undefined, (reader, target, left) => {
|
|
|
8638
9343
|
}
|
|
8639
9344
|
else {
|
|
8640
9345
|
reader.logMissingFeatures && reader.log('Unhandled subsection in #4000', key);
|
|
9346
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
8641
9347
|
}
|
|
8642
9348
|
});
|
|
8643
9349
|
}
|
|
8644
9350
|
});
|
|
9351
|
+
(0, psdReader_1.skipBytes)(reader, left()); // unknown data after animations section
|
|
8645
9352
|
}
|
|
8646
9353
|
else if (key === 'mopt') {
|
|
8647
9354
|
const bytes = (0, psdReader_1.readBytes)(reader, left());
|
|
8648
9355
|
reader.logDevFeatures && reader.log('#4000 mopt', bytes);
|
|
8649
9356
|
}
|
|
8650
9357
|
else {
|
|
8651
|
-
reader.logMissingFeatures && reader.log(
|
|
9358
|
+
reader.logMissingFeatures && reader.log(`Unhandled plug-in resource key: ${key}`);
|
|
9359
|
+
(0, psdReader_1.skipBytes)(reader, left());
|
|
8652
9360
|
}
|
|
8653
|
-
}, (writer, target) => {
|
|
8654
|
-
|
|
9361
|
+
}, (writer, target, index) => {
|
|
9362
|
+
var _a, _b;
|
|
9363
|
+
const key = pluginResourceKeys(target)[index];
|
|
9364
|
+
if (key === 'mset') {
|
|
9365
|
+
(0, psdWriter_1.writeSignature)(writer, 'mset');
|
|
9366
|
+
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', target.outputSettings, descriptor_1.outputSettingsRoot);
|
|
9367
|
+
}
|
|
9368
|
+
else if (key === 'mfri') {
|
|
9369
|
+
const animations = target.animations;
|
|
9370
|
+
(0, psdWriter_1.writeSignature)(writer, 'mfri');
|
|
9371
|
+
(0, psdWriter_1.writeUint32)(writer, 2); // version
|
|
9372
|
+
(0, psdWriter_1.writeUint32)(writer, 16); // length
|
|
9373
|
+
(0, psdWriter_1.writeUint32)(writer, animations.frames.length);
|
|
9374
|
+
(0, psdWriter_1.writeUint32)(writer, (_b = (_a = animations.animations[0]) === null || _a === void 0 ? void 0 : _a.activeFrame) !== null && _b !== void 0 ? _b : 0);
|
|
9375
|
+
(0, psdWriter_1.writeUint32)(writer, animations.animations.length);
|
|
9376
|
+
(0, psdWriter_1.writeUint32)(writer, 0);
|
|
9377
|
+
}
|
|
9378
|
+
else if (key === 'mani') {
|
|
8655
9379
|
(0, psdWriter_1.writeSignature)(writer, 'mani');
|
|
8656
9380
|
(0, psdWriter_1.writeSignature)(writer, 'IRFR');
|
|
8657
9381
|
(0, psdWriter_1.writeSection)(writer, 1, () => {
|
|
@@ -8693,46 +9417,9 @@ target => target.animations !== undefined, (reader, target, left) => {
|
|
|
8693
9417
|
// });
|
|
8694
9418
|
});
|
|
8695
9419
|
}
|
|
8696
|
-
});
|
|
8697
|
-
// TODO: Unfinished
|
|
8698
|
-
helpers_1.MOCK_HANDLERS && addHandler(4001, // Plug-In resource(s)
|
|
8699
|
-
// Plug-In resource(s)
|
|
8700
|
-
target => target._ir4001 !== undefined, (reader, target, left) => {
|
|
8701
|
-
if (helpers_1.MOCK_HANDLERS) {
|
|
8702
|
-
LOG_MOCK_HANDLERS && console.log('image resource 4001', left());
|
|
8703
|
-
target._ir4001 = (0, psdReader_1.readBytes)(reader, left());
|
|
8704
|
-
return;
|
|
8705
|
-
}
|
|
8706
|
-
const key = (0, psdReader_1.readSignature)(reader);
|
|
8707
|
-
if (key === 'mfri') {
|
|
8708
|
-
const version = (0, psdReader_1.readUint32)(reader);
|
|
8709
|
-
if (version !== 2)
|
|
8710
|
-
throw new Error('Invalid mfri version');
|
|
8711
|
-
const length = (0, psdReader_1.readUint32)(reader);
|
|
8712
|
-
const bytes = (0, psdReader_1.readBytes)(reader, length);
|
|
8713
|
-
reader.logDevFeatures && reader.log('mfri', bytes);
|
|
8714
|
-
}
|
|
8715
|
-
else if (key === 'mset') {
|
|
8716
|
-
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
8717
|
-
reader.logDevFeatures && reader.log('mset', desc);
|
|
8718
|
-
}
|
|
8719
|
-
else {
|
|
8720
|
-
reader.logMissingFeatures && reader.log('Unhandled key in #4001', key);
|
|
8721
|
-
}
|
|
8722
|
-
}, (writer, target) => {
|
|
8723
|
-
(0, psdWriter_1.writeBytes)(writer, target._ir4001);
|
|
8724
|
-
});
|
|
8725
|
-
// TODO: Unfinished
|
|
8726
|
-
helpers_1.MOCK_HANDLERS && addHandler(4002, // Plug-In resource(s)
|
|
8727
|
-
// Plug-In resource(s)
|
|
8728
|
-
target => target._ir4002 !== undefined, (reader, target, left) => {
|
|
8729
|
-
LOG_MOCK_HANDLERS && console.log('image resource 4002', left());
|
|
8730
|
-
target._ir4002 = (0, psdReader_1.readBytes)(reader, left());
|
|
8731
|
-
}, (writer, target) => {
|
|
8732
|
-
(0, psdWriter_1.writeBytes)(writer, target._ir4002);
|
|
8733
|
-
});
|
|
9420
|
+
}, { keyCount: 1000 });
|
|
8734
9421
|
|
|
8735
|
-
},{"./descriptor":4,"./helpers":8,"./psdReader":13,"./psdWriter":14,"./utf8":16,"base64-js":17}],10:[function(require,module,exports){
|
|
9422
|
+
},{"./additionalInfo":2,"./descriptor":4,"./helpers":8,"./psdReader":13,"./psdWriter":14,"./utf8":16,"base64-js":17}],10:[function(require,module,exports){
|
|
8736
9423
|
(function (Buffer){(function (){
|
|
8737
9424
|
"use strict";
|
|
8738
9425
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
@@ -9458,7 +10145,7 @@ function parse(data) {
|
|
|
9458
10145
|
};
|
|
9459
10146
|
}
|
|
9460
10147
|
}
|
|
9461
|
-
//
|
|
10148
|
+
// APP1 - Exif
|
|
9462
10149
|
if (fileMarker === 0xFFE1) {
|
|
9463
10150
|
if (appData[0] === 0x45 &&
|
|
9464
10151
|
appData[1] === 0x78 &&
|
|
@@ -9641,12 +10328,12 @@ function parse(data) {
|
|
|
9641
10328
|
// set each frame's components quantization table
|
|
9642
10329
|
for (let i = 0; i < frames.length; i++) {
|
|
9643
10330
|
const cp = frames[i].components;
|
|
9644
|
-
for (
|
|
9645
|
-
const
|
|
10331
|
+
for (const key of Object.keys(cp)) {
|
|
10332
|
+
const component = cp[+key];
|
|
10333
|
+
const table = quantizationTables[component.quantizationIdx];
|
|
9646
10334
|
if (!table)
|
|
9647
|
-
throw new Error(`Missing quantization table ${
|
|
9648
|
-
|
|
9649
|
-
delete cp[j].quantizationIdx; // TODO: why ???
|
|
10335
|
+
throw new Error(`Missing quantization table ${component.quantizationIdx}`);
|
|
10336
|
+
component.quantizationTable = table;
|
|
9650
10337
|
}
|
|
9651
10338
|
}
|
|
9652
10339
|
self.width = frame.samplesPerLine;
|
|
@@ -9701,8 +10388,8 @@ function getData(decoded) {
|
|
|
9701
10388
|
break;
|
|
9702
10389
|
}
|
|
9703
10390
|
case 3: {
|
|
9704
|
-
// The default transform for three components is true, the adobe transform marker overrides it
|
|
9705
|
-
colorTransform = decoded.adobe ? !!decoded.adobe.transformCode : true;
|
|
10391
|
+
// The default transform for three components is true, JFIF marker implies YCbCr, otherwise the adobe transform marker overrides it
|
|
10392
|
+
colorTransform = decoded.jfif ? true : decoded.adobe ? !!decoded.adobe.transformCode : true;
|
|
9706
10393
|
const component1 = decoded.components[0];
|
|
9707
10394
|
const component2 = decoded.components[1];
|
|
9708
10395
|
const component3 = decoded.components[2];
|
|
@@ -9916,6 +10603,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9916
10603
|
};
|
|
9917
10604
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9918
10605
|
exports.supportedColorModes = void 0;
|
|
10606
|
+
exports.getUtf8Decoder = getUtf8Decoder;
|
|
10607
|
+
exports.getUtf8StrictDecoder = getUtf8StrictDecoder;
|
|
10608
|
+
exports.getGbkStrictDecoder = getGbkStrictDecoder;
|
|
10609
|
+
exports.decodeUtf8 = decodeUtf8;
|
|
9919
10610
|
exports.createReader = createReader;
|
|
9920
10611
|
exports.warnOrThrow = warnOrThrow;
|
|
9921
10612
|
exports.readUint8 = readUint8;
|
|
@@ -9957,12 +10648,15 @@ exports.readDataZip = readDataZip;
|
|
|
9957
10648
|
exports.readDataRLE = readDataRLE;
|
|
9958
10649
|
exports.readSection = readSection;
|
|
9959
10650
|
exports.readColor = readColor;
|
|
10651
|
+
exports.readPatternSafe = readPatternSafe;
|
|
9960
10652
|
exports.readPattern = readPattern;
|
|
10653
|
+
exports.consumeMemory = consumeMemory;
|
|
9961
10654
|
const pako_1 = require("pako");
|
|
9962
10655
|
const helpers_1 = require("./helpers");
|
|
9963
10656
|
const additionalInfo_1 = require("./additionalInfo");
|
|
10657
|
+
const utf8_1 = require("./utf8");
|
|
9964
10658
|
const imageResources_1 = require("./imageResources");
|
|
9965
|
-
exports.supportedColorModes = [0 /* ColorMode.Bitmap */, 1 /* ColorMode.Grayscale */, 3 /* ColorMode.RGB */, 2 /* ColorMode.Indexed */];
|
|
10659
|
+
exports.supportedColorModes = [0 /* ColorMode.Bitmap */, 1 /* ColorMode.Grayscale */, 3 /* ColorMode.RGB */, 2 /* ColorMode.Indexed */, 4 /* ColorMode.CMYK */];
|
|
9966
10660
|
const colorModes = ['bitmap', 'grayscale', 'indexed', 'RGB', 'CMYK', '', '', 'multichannel', 'duotone', 'lab'];
|
|
9967
10661
|
function setupGrayscale(data) {
|
|
9968
10662
|
const size = data.width * data.height * 4;
|
|
@@ -9972,6 +10666,37 @@ function setupGrayscale(data) {
|
|
|
9972
10666
|
data.data[i + 2] = c;
|
|
9973
10667
|
}
|
|
9974
10668
|
}
|
|
10669
|
+
function createTextDecoder(label, options) {
|
|
10670
|
+
try {
|
|
10671
|
+
return typeof TextDecoder !== 'undefined' ? new TextDecoder(label, options) : null;
|
|
10672
|
+
}
|
|
10673
|
+
catch (_a) {
|
|
10674
|
+
return null; // encoding not supported
|
|
10675
|
+
}
|
|
10676
|
+
}
|
|
10677
|
+
// non-fatal UTF-8 decoder, malformed byte sequences are replaced with U+FFFD
|
|
10678
|
+
function getUtf8Decoder(reader) {
|
|
10679
|
+
if (reader.utf8Decoder === undefined)
|
|
10680
|
+
reader.utf8Decoder = createTextDecoder('utf-8', { ignoreBOM: true });
|
|
10681
|
+
return reader.utf8Decoder;
|
|
10682
|
+
}
|
|
10683
|
+
// UTF-8 decoder that throws on malformed byte sequences
|
|
10684
|
+
function getUtf8StrictDecoder(reader) {
|
|
10685
|
+
if (reader.utf8StrictDecoder === undefined)
|
|
10686
|
+
reader.utf8StrictDecoder = createTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
10687
|
+
return reader.utf8StrictDecoder;
|
|
10688
|
+
}
|
|
10689
|
+
// GBK decoder that throws on malformed byte sequences
|
|
10690
|
+
function getGbkStrictDecoder(reader) {
|
|
10691
|
+
if (reader.gbkDecoder === undefined)
|
|
10692
|
+
reader.gbkDecoder = createTextDecoder('gbk', { fatal: true });
|
|
10693
|
+
return reader.gbkDecoder;
|
|
10694
|
+
}
|
|
10695
|
+
function decodeUtf8(reader, buffer) {
|
|
10696
|
+
// native decoder is faster only for longer strings
|
|
10697
|
+
const decoder = buffer.byteLength > 1000 ? getUtf8Decoder(reader) : null;
|
|
10698
|
+
return decoder ? decoder.decode(buffer) : (0, utf8_1.decodeString)(buffer);
|
|
10699
|
+
}
|
|
9975
10700
|
function createReader(buffer, offset, length) {
|
|
9976
10701
|
const view = new DataView(buffer, offset, length);
|
|
9977
10702
|
return { view, offset: 0, strict: false, debug: false, large: false, globalAlpha: false, log: console.log };
|
|
@@ -10151,7 +10876,8 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10151
10876
|
const maxSize = version === 1 ? 30000 : 300000;
|
|
10152
10877
|
if (width > maxSize || height > maxSize)
|
|
10153
10878
|
throw new Error(`Invalid size: ${width}x${height}`);
|
|
10154
|
-
|
|
10879
|
+
// up to 56 channels plus transparency of composite image (Photoshop CS3 writes 57 channels for 53 alpha channels)
|
|
10880
|
+
if (channels < 1 || channels > 57)
|
|
10155
10881
|
throw new Error(`Invalid channel count: ${channels}`);
|
|
10156
10882
|
if (![1, 8, 16, 32].includes(bitsPerChannel))
|
|
10157
10883
|
throw new Error(`Invalid bitsPerChannel: ${bitsPerChannel}`);
|
|
@@ -10161,6 +10887,7 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10161
10887
|
Object.assign(reader, readOptions);
|
|
10162
10888
|
reader.large = version === 2;
|
|
10163
10889
|
reader.globalAlpha = false;
|
|
10890
|
+
reader.layersInGlobalInfo = false;
|
|
10164
10891
|
if (!('totalMemoryLimit' in reader)) { // setting totalMemoryLimit to undefined explicitly disables memory limit
|
|
10165
10892
|
reader.totalMemoryLimit = 2 * 1024 * 1024 * 1024; // default 2GB memory limit
|
|
10166
10893
|
}
|
|
@@ -10188,17 +10915,21 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10188
10915
|
});
|
|
10189
10916
|
// image resources
|
|
10190
10917
|
const imageResources = {};
|
|
10918
|
+
let unreadResourceBytes = 0;
|
|
10191
10919
|
readSection(reader, 1, left => {
|
|
10192
|
-
|
|
10193
|
-
|
|
10920
|
+
// stop if there's not enough data left for resource header (some files have few trailing bytes in this section)
|
|
10921
|
+
while (left() >= 12) {
|
|
10922
|
+
const signature = realignWithSignature(reader, isValidSignature);
|
|
10194
10923
|
const id = readUint16(reader);
|
|
10195
|
-
|
|
10924
|
+
const nameLength = readUint8(reader);
|
|
10925
|
+
const name = readBytes(reader, nameLength);
|
|
10926
|
+
skipBytes(reader, (nameLength + 1) % 2); // pad to even size
|
|
10196
10927
|
readSection(reader, 2, left => {
|
|
10197
10928
|
const handler = imageResources_1.resourceHandlersMap[id];
|
|
10198
10929
|
const skip = id === 1036 && !!reader.skipThumbnail;
|
|
10199
10930
|
if (handler && !skip) {
|
|
10200
10931
|
try {
|
|
10201
|
-
handler.read(reader, imageResources, left);
|
|
10932
|
+
handler.read(reader, imageResources, left, { signature, id, name, width, height });
|
|
10202
10933
|
}
|
|
10203
10934
|
catch (e) {
|
|
10204
10935
|
if (reader.throwForMissingFeatures)
|
|
@@ -10207,13 +10938,20 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10207
10938
|
}
|
|
10208
10939
|
}
|
|
10209
10940
|
else {
|
|
10210
|
-
|
|
10941
|
+
reader.logMissingFeatures && reader.log(`Unhandled image resource: ${id} (${left()})`);
|
|
10211
10942
|
skipBytes(reader, left());
|
|
10212
10943
|
}
|
|
10213
10944
|
});
|
|
10214
10945
|
}
|
|
10946
|
+
unreadResourceBytes = left();
|
|
10947
|
+
skipBytes(reader, left());
|
|
10215
10948
|
});
|
|
10216
|
-
|
|
10949
|
+
// some files have image resources section length few bytes larger than the data, layer and mask info section
|
|
10950
|
+
// starts right after the last resource in that case
|
|
10951
|
+
if (unreadResourceBytes && !sectionFits(reader, reader.offset) && sectionFits(reader, reader.offset - unreadResourceBytes)) {
|
|
10952
|
+
reader.offset -= unreadResourceBytes;
|
|
10953
|
+
}
|
|
10954
|
+
const { layersGroup, layerGroupsEnabledId, savedPathsOrigination } = imageResources, rest = __rest(imageResources, ["layersGroup", "layerGroupsEnabledId", "savedPathsOrigination"]);
|
|
10217
10955
|
if (Object.keys(rest).length) {
|
|
10218
10956
|
psd.imageResources = rest;
|
|
10219
10957
|
}
|
|
@@ -10257,6 +10995,8 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10257
10995
|
const rawCompositeData = new Uint8Array(reader.view.buffer, reader.view.byteOffset + rawOffset, reader.view.byteLength - rawOffset);
|
|
10258
10996
|
psd.rawCompositeData = rawCompositeData;
|
|
10259
10997
|
psd.rawCompositeDataInfo = { large: reader.large, globalAlpha: reader.globalAlpha };
|
|
10998
|
+
if (reader.layersInGlobalInfo)
|
|
10999
|
+
psd.rawCompositeDataInfo.layersInGlobalInfo = true;
|
|
10260
11000
|
}
|
|
10261
11001
|
else {
|
|
10262
11002
|
const imageData = readImageData(reader, psd);
|
|
@@ -10268,9 +11008,6 @@ function readPsd(reader, readOptions = {}) {
|
|
|
10268
11008
|
}
|
|
10269
11009
|
}
|
|
10270
11010
|
}
|
|
10271
|
-
// TODO: show converted color mode instead of original PSD file color mode
|
|
10272
|
-
// but add option to preserve file color mode (need to return image data instead of canvas in that case)
|
|
10273
|
-
// psd.colorMode = ColorMode.RGB; // we convert all color modes to RGB
|
|
10274
11011
|
return psd;
|
|
10275
11012
|
}
|
|
10276
11013
|
function readLayerInfo(reader, psd, imageResources) {
|
|
@@ -10346,9 +11083,12 @@ function readLayerRecord(reader, psd, imageResources) {
|
|
|
10346
11083
|
}
|
|
10347
11084
|
checkSignature(reader, '8BIM');
|
|
10348
11085
|
const blendMode = readSignature(reader);
|
|
10349
|
-
if (!helpers_1.toBlendMode[blendMode])
|
|
10350
|
-
|
|
10351
|
-
|
|
11086
|
+
if (!helpers_1.toBlendMode[blendMode]) {
|
|
11087
|
+
if (reader.throwForMissingFeatures)
|
|
11088
|
+
throw new Error(`Invalid blend mode: '${blendMode}'`);
|
|
11089
|
+
reader.logMissingFeatures && reader.log(`Unknown blend mode: '${blendMode}', using normal blend mode`);
|
|
11090
|
+
}
|
|
11091
|
+
layer.blendMode = helpers_1.toBlendMode[blendMode] || 'normal';
|
|
10352
11092
|
layer.opacity = readUint8(reader) / 0xff;
|
|
10353
11093
|
layer.clipping = readUint8(reader) === 1;
|
|
10354
11094
|
const flags = readUint8(reader);
|
|
@@ -10376,11 +11116,20 @@ function readLayerRecord(reader, psd, imageResources) {
|
|
|
10376
11116
|
});
|
|
10377
11117
|
return { layer, channels };
|
|
10378
11118
|
}
|
|
11119
|
+
// negative sizes are treated as empty (Photoshop writes them for some empty layers, like 0,0,-1,0 bounds of fill layer)
|
|
11120
|
+
// checks if length of section (layer and mask info) at given offset fits in the file
|
|
11121
|
+
function sectionFits(reader, offset) {
|
|
11122
|
+
const lengthSize = reader.large ? 8 : 4;
|
|
11123
|
+
if (offset < 0 || offset + lengthSize > reader.view.byteLength)
|
|
11124
|
+
return false;
|
|
11125
|
+
const length = reader.large ? reader.view.getUint32(offset) * 0x100000000 + reader.view.getUint32(offset + 4) : reader.view.getUint32(offset);
|
|
11126
|
+
return offset + lengthSize + length <= reader.view.byteLength;
|
|
11127
|
+
}
|
|
10379
11128
|
function isValidBoxSize(box, reader) {
|
|
10380
11129
|
const width = (box.right || 0) - (box.left || 0);
|
|
10381
11130
|
const height = (box.bottom || 0) - (box.top || 0);
|
|
10382
11131
|
const maxSize = reader.large ? 300000 : 30000;
|
|
10383
|
-
return width
|
|
11132
|
+
return width <= maxSize && height <= maxSize;
|
|
10384
11133
|
}
|
|
10385
11134
|
function readLayerMaskData(reader, layer) {
|
|
10386
11135
|
return readSection(reader, 1, left => {
|
|
@@ -10499,9 +11248,9 @@ function readLayerChannelImageData(reader, psd, layer, channels) {
|
|
|
10499
11248
|
reader.offset -= 1;
|
|
10500
11249
|
compression = readUint16(reader);
|
|
10501
11250
|
}
|
|
10502
|
-
// try to fix broken files where there's 1 byte shift of channel
|
|
11251
|
+
// try to fix broken files where there's 1 byte shift of channel (in the other direction)
|
|
10503
11252
|
if (compression > 3) {
|
|
10504
|
-
reader.offset -=
|
|
11253
|
+
reader.offset -= 4;
|
|
10505
11254
|
compression = readUint16(reader);
|
|
10506
11255
|
}
|
|
10507
11256
|
if (compression > 3)
|
|
@@ -10535,6 +11284,7 @@ function getCompositeImageData(psd) {
|
|
|
10535
11284
|
if (info) {
|
|
10536
11285
|
reader.large = info.large;
|
|
10537
11286
|
reader.globalAlpha = info.globalAlpha;
|
|
11287
|
+
reader.layersInGlobalInfo = !!info.layersInGlobalInfo;
|
|
10538
11288
|
}
|
|
10539
11289
|
return readImageData(reader, psd);
|
|
10540
11290
|
}
|
|
@@ -10615,18 +11365,14 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, log
|
|
|
10615
11365
|
let initializedAlpha = false;
|
|
10616
11366
|
if (layerWidth && layerHeight && read === LayerDataType.Layer) {
|
|
10617
11367
|
if (cmyk) {
|
|
10618
|
-
if (bitsPerChannel !== 8)
|
|
11368
|
+
if (bitsPerChannel !== 8 && bitsPerChannel !== 16)
|
|
10619
11369
|
throw new Error('bitsPerChannel not supported');
|
|
10620
|
-
imageData =
|
|
11370
|
+
imageData = createImageDataBitDepth(layerWidth, layerHeight, bitsPerChannel, 5, memoryLimit);
|
|
10621
11371
|
}
|
|
10622
11372
|
else {
|
|
10623
11373
|
imageData = createImageDataBitDepth(layerWidth, layerHeight, bitsPerChannel, 4, memoryLimit);
|
|
10624
11374
|
}
|
|
10625
11375
|
}
|
|
10626
|
-
if (helpers_1.RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
|
|
10627
|
-
layer.imageDataRaw = [];
|
|
10628
|
-
layer.imageDataRawCompression = [];
|
|
10629
|
-
}
|
|
10630
11376
|
for (const { id, compression, data } of channels) {
|
|
10631
11377
|
if (!data)
|
|
10632
11378
|
continue;
|
|
@@ -10651,16 +11397,6 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, log
|
|
|
10651
11397
|
if (memoryLimit !== undefined)
|
|
10652
11398
|
dataReader.totalMemoryLimit = Math.max(0, dataReader.totalMemoryLimit - maskData.data.byteLength);
|
|
10653
11399
|
readData(dataReader, data.byteLength, maskData, compression, maskWidth, maskHeight, bitsPerChannel, 0, large, 4);
|
|
10654
|
-
if (helpers_1.RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
|
|
10655
|
-
if (id === -2 /* ChannelID.UserMask */) {
|
|
10656
|
-
layer.maskDataRawCompression = compression;
|
|
10657
|
-
layer.maskDataRaw = data;
|
|
10658
|
-
}
|
|
10659
|
-
else {
|
|
10660
|
-
layer.realMaskDataRawCompression = compression;
|
|
10661
|
-
layer.realMaskDataRaw = data;
|
|
10662
|
-
}
|
|
10663
|
-
}
|
|
10664
11400
|
setupGrayscale(maskData);
|
|
10665
11401
|
resetAlpha(maskData, false);
|
|
10666
11402
|
}
|
|
@@ -10677,10 +11413,6 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, log
|
|
|
10677
11413
|
}
|
|
10678
11414
|
}
|
|
10679
11415
|
readData(dataReader, data.byteLength, targetData, compression, layerWidth, layerHeight, bitsPerChannel, offset, large, cmyk ? 5 : 4);
|
|
10680
|
-
if (helpers_1.RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
|
|
10681
|
-
layer.imageDataRawCompression[id] = compression;
|
|
10682
|
-
layer.imageDataRaw[id] = data;
|
|
10683
|
-
}
|
|
10684
11416
|
}
|
|
10685
11417
|
if (id === -1 /* ChannelID.Transparency */) {
|
|
10686
11418
|
initializedAlpha = true;
|
|
@@ -10693,7 +11425,8 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, log
|
|
|
10693
11425
|
resetAlpha(imageData, cmyk);
|
|
10694
11426
|
if (cmyk) {
|
|
10695
11427
|
const cmykData = imageData;
|
|
10696
|
-
|
|
11428
|
+
const rgbMemoryLimit = memoryLimit === undefined ? undefined : Math.max(0, memoryLimit - cmykData.data.byteLength);
|
|
11429
|
+
imageData = createImageDataBitDepth(cmykData.width, cmykData.height, bitsPerChannel, 4, rgbMemoryLimit);
|
|
10697
11430
|
cmykToRgb(cmykData, imageData, false);
|
|
10698
11431
|
}
|
|
10699
11432
|
}
|
|
@@ -10766,7 +11499,15 @@ function readAdditionalLayerInfo(reader, target, psd, imageResources) {
|
|
|
10766
11499
|
const sig = realignWithSignature(reader, isValidAdditionalInfoSignature);
|
|
10767
11500
|
const key = readSignature(reader);
|
|
10768
11501
|
// `largeAdditionalInfoKeys` fallback, because some keys don't have 8B64 signature even when they are 64bit
|
|
10769
|
-
|
|
11502
|
+
let u64 = sig === '8B64' || (reader.large && helpers_1.largeAdditionalInfoKeys.indexOf(key) !== -1);
|
|
11503
|
+
// these keys were written by older versions of this library with 32bit length and 8BIM signature,
|
|
11504
|
+
// 64bit length always has high 32bits set to 0 (lengths over 4GB are not supported)
|
|
11505
|
+
if (reader.large && sig === '8BIM' && helpers_1.largeAdditionalInfoKeysObserved.indexOf(key) !== -1) {
|
|
11506
|
+
// 32bit length of 0 is followed by signature of the next block, 64bit length would continue with its low 32bits
|
|
11507
|
+
const next = reader.offset + 8 <= reader.view.byteLength ? reader.view.getUint32(reader.offset + 4) : 0;
|
|
11508
|
+
const nextIsSignature = next === 0x3842494d /* 8BIM */ || next === 0x38423634 /* 8B64 */;
|
|
11509
|
+
u64 = reader.view.getUint32(reader.offset) === 0 && !nextIsSignature;
|
|
11510
|
+
}
|
|
10770
11511
|
readSection(reader, 2, left => {
|
|
10771
11512
|
const handler = additionalInfo_1.infoHandlersMap[key];
|
|
10772
11513
|
if (handler) {
|
|
@@ -10779,7 +11520,7 @@ function readAdditionalLayerInfo(reader, target, psd, imageResources) {
|
|
|
10779
11520
|
}
|
|
10780
11521
|
}
|
|
10781
11522
|
else {
|
|
10782
|
-
reader.logMissingFeatures && reader.log(`Unhandled additional info: ${key}`);
|
|
11523
|
+
reader.logMissingFeatures && key !== 'GenI' && key !== 'OCIO' && key !== 'CAI ' && reader.log(`Unhandled additional info: ${key}`);
|
|
10783
11524
|
skipBytes(reader, left());
|
|
10784
11525
|
}
|
|
10785
11526
|
if (left()) {
|
|
@@ -10811,7 +11552,7 @@ function createImageDataBitDepth(width, height, bitDepth, channels, memoryLimit)
|
|
|
10811
11552
|
}
|
|
10812
11553
|
}
|
|
10813
11554
|
function readImageData(reader, psd) {
|
|
10814
|
-
var _a;
|
|
11555
|
+
var _a, _b, _c;
|
|
10815
11556
|
const compression = readUint16(reader);
|
|
10816
11557
|
const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
10817
11558
|
const { width, height } = psd;
|
|
@@ -10843,11 +11584,7 @@ function readImageData(reader, psd) {
|
|
|
10843
11584
|
case 1 /* ColorMode.Grayscale */: {
|
|
10844
11585
|
const colorChannels = psd.colorMode === 1 /* ColorMode.Grayscale */ ? 1 : 3;
|
|
10845
11586
|
const offsets = compositeChannelOffsets(reader, psd, colorChannels, 3);
|
|
10846
|
-
const start = reader.offset;
|
|
10847
11587
|
readCompositeChannels(reader, compression, imageData, bitsPerChannel, 4, offsets);
|
|
10848
|
-
if (helpers_1.RAW_IMAGE_DATA && compression === 1 /* Compression.RleCompressed */) {
|
|
10849
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
10850
|
-
}
|
|
10851
11588
|
if (psd.colorMode === 1 /* ColorMode.Grayscale */) {
|
|
10852
11589
|
setupGrayscale(imageData);
|
|
10853
11590
|
}
|
|
@@ -10861,41 +11598,42 @@ function readImageData(reader, psd) {
|
|
|
10861
11598
|
const offsets = compositeChannelOffsets(reader, psd, 1, -1);
|
|
10862
11599
|
const indexedImageData = { width, height, data: new Uint8Array(width * height) };
|
|
10863
11600
|
readCompositeChannels(reader, compression, indexedImageData, 8, 1, offsets);
|
|
10864
|
-
indexedToRgb(indexedImageData, imageData, psd.palette);
|
|
11601
|
+
indexedToRgb(indexedImageData, imageData, psd.palette, (_c = (_b = psd.imageResources) === null || _b === void 0 ? void 0 : _b.transparencyIndex) !== null && _c !== void 0 ? _c : -1);
|
|
10865
11602
|
break;
|
|
10866
11603
|
}
|
|
10867
11604
|
case 4 /* ColorMode.CMYK */: {
|
|
10868
|
-
if (bitsPerChannel !== 8)
|
|
11605
|
+
if (bitsPerChannel !== 8 && bitsPerChannel !== 16)
|
|
10869
11606
|
throw new Error('bitsPerChannel not supported');
|
|
10870
11607
|
const offsets = compositeChannelOffsets(reader, psd, 4, 4);
|
|
10871
|
-
const cmykImageData =
|
|
10872
|
-
|
|
10873
|
-
readCompositeChannels(reader, compression, cmykImageData,
|
|
10874
|
-
cmykToRgb(cmykImageData, imageData,
|
|
10875
|
-
if (helpers_1.RAW_IMAGE_DATA && compression === 1 /* Compression.RleCompressed */) {
|
|
10876
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
10877
|
-
}
|
|
11608
|
+
const cmykImageData = createImageDataBitDepth(width, height, bitsPerChannel, 5, reader.totalMemoryLimit);
|
|
11609
|
+
resetAlpha(cmykImageData, true);
|
|
11610
|
+
readCompositeChannels(reader, compression, cmykImageData, bitsPerChannel, 5, offsets);
|
|
11611
|
+
cmykToRgb(cmykImageData, imageData, !!reader.globalAlpha);
|
|
10878
11612
|
break;
|
|
10879
11613
|
}
|
|
10880
11614
|
default: throw new Error(`Color mode not supported: ${psd.colorMode}`);
|
|
10881
11615
|
}
|
|
10882
|
-
// remove weird white matte
|
|
10883
|
-
if (reader.globalAlpha) {
|
|
11616
|
+
// remove weird white matte (already removed when converting from CMYK)
|
|
11617
|
+
if (reader.globalAlpha && psd.colorMode !== 4 /* ColorMode.CMYK */) {
|
|
10884
11618
|
removeWhiteMatte(imageData);
|
|
10885
11619
|
}
|
|
10886
11620
|
return imageData;
|
|
10887
11621
|
}
|
|
10888
11622
|
// returns target offset for each of the composite image channels stored in the file, -1 for channels that are skipped
|
|
10889
11623
|
function compositeChannelOffsets(reader, psd, colorChannels, alphaOffset) {
|
|
10890
|
-
var _a, _b, _c
|
|
11624
|
+
var _a, _b, _c;
|
|
10891
11625
|
const channelCount = (_a = psd.channels) !== null && _a !== void 0 ? _a : (colorChannels + (reader.globalAlpha ? 1 : 0));
|
|
10892
11626
|
if (channelCount < colorChannels)
|
|
10893
11627
|
throw new Error(`Invalid channel count: ${channelCount}`);
|
|
10894
11628
|
// First extra channel is transparency if document has global alpha (negative layer count). Some non-Photoshop
|
|
10895
11629
|
// applications write transparency channel without setting global alpha, in that case extra channel is not
|
|
10896
11630
|
// listed in alpha channel names (Photoshop names all user alpha channels / saved selections).
|
|
10897
|
-
|
|
10898
|
-
|
|
11631
|
+
// Photoshop also lists merged transparency as first alpha channel named "Transparency" (in documents marked with
|
|
11632
|
+
// Mtrn/Mt16/Mt32 additional info, or in some 16bit documents with layers stored in Lr16 without any other mark)
|
|
11633
|
+
const alphaNames = (_c = (_b = psd.imageResources) === null || _b === void 0 ? void 0 : _b.alphaChannelNames) !== null && _c !== void 0 ? _c : [];
|
|
11634
|
+
const namedChannels = alphaNames.length;
|
|
11635
|
+
const namedTransparency = !!reader.layersInGlobalInfo && alphaNames[0] === 'Transparency' && namedChannels === channelCount - colorChannels;
|
|
11636
|
+
const hasTransparency = reader.globalAlpha || namedTransparency || (channelCount - colorChannels) > namedChannels;
|
|
10899
11637
|
const offsets = [];
|
|
10900
11638
|
for (let i = 0; i < channelCount; i++) {
|
|
10901
11639
|
if (i < colorChannels) {
|
|
@@ -10974,41 +11712,67 @@ function removeWhiteMatte({ data, width, height }) {
|
|
|
10974
11712
|
}
|
|
10975
11713
|
}
|
|
10976
11714
|
}
|
|
10977
|
-
|
|
11715
|
+
// converts value in 0-255 range to target range, rounding and clamping it
|
|
11716
|
+
function toRange(value, max) {
|
|
11717
|
+
value = Math.round(value * (max / 255));
|
|
11718
|
+
return value <= 0 ? 0 : (value >= max ? max : value);
|
|
11719
|
+
}
|
|
11720
|
+
// Polynomial approximation of U.S. Web Coated (SWOP) v2 CMYK to RGB conversion (default CMYK profile of Photoshop).
|
|
11721
|
+
// Coefficients are taken from pdf.js (DeviceCmykCS in src/core/colorspace.js, https://github.com/mozilla/pdf.js),
|
|
11722
|
+
// Copyright 2012 Mozilla Foundation, licensed under the Apache License, Version 2.0
|
|
11723
|
+
// (http://www.apache.org/licenses/LICENSE-2.0)
|
|
11724
|
+
// cmyk - 8 or 16 bit data with 5 channels (cmyka), rgb - 8 or 16 bit data with 4 channels (rgba)
|
|
11725
|
+
// removeMatte - colors are blended with white (no ink), used for composite image of documents with global alpha
|
|
11726
|
+
function cmykToRgb(cmyk, rgb, removeMatte) {
|
|
10978
11727
|
const size = rgb.width * rgb.height * 4;
|
|
10979
11728
|
const srcData = cmyk.data;
|
|
10980
11729
|
const dstData = rgb.data;
|
|
11730
|
+
const srcMax = srcData instanceof Uint16Array ? 0xffff : 0xff;
|
|
11731
|
+
const dstMax = dstData instanceof Uint16Array ? 0xffff : 0xff;
|
|
10981
11732
|
for (let src = 0, dst = 0; dst < size; src += 5, dst += 4) {
|
|
10982
|
-
const
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11733
|
+
const a = srcData[src + 4];
|
|
11734
|
+
// image data stores inverted values (0 = 100% ink)
|
|
11735
|
+
let c = 1 - srcData[src] / srcMax;
|
|
11736
|
+
let m = 1 - srcData[src + 1] / srcMax;
|
|
11737
|
+
let y = 1 - srcData[src + 2] / srcMax;
|
|
11738
|
+
let k = 1 - srcData[src + 3] / srcMax;
|
|
11739
|
+
if (removeMatte && a > 0 && a < srcMax) {
|
|
11740
|
+
const ra = srcMax / a;
|
|
11741
|
+
c = Math.min(1, c * ra);
|
|
11742
|
+
m = Math.min(1, m * ra);
|
|
11743
|
+
y = Math.min(1, y * ra);
|
|
11744
|
+
k = Math.min(1, k * ra);
|
|
11745
|
+
}
|
|
11746
|
+
dstData[dst] = toRange(255 +
|
|
11747
|
+
c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) +
|
|
11748
|
+
m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) +
|
|
11749
|
+
y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) +
|
|
11750
|
+
k * (-21.86122147463605 * k - 189.48180835922747), dstMax);
|
|
11751
|
+
dstData[dst + 1] = toRange(255 +
|
|
11752
|
+
c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) +
|
|
11753
|
+
m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) +
|
|
11754
|
+
y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
|
|
11755
|
+
k * (-20.737325471181034 * k - 187.80453709719578), dstMax);
|
|
11756
|
+
dstData[dst + 2] = toRange(255 +
|
|
11757
|
+
c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) +
|
|
11758
|
+
m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) +
|
|
11759
|
+
y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) +
|
|
11760
|
+
k * (-22.33816807309886 * k - 180.12613974708367), dstMax);
|
|
11761
|
+
dstData[dst + 3] = srcMax === dstMax ? a : Math.round(a * dstMax / srcMax);
|
|
11762
|
+
}
|
|
11763
|
+
}
|
|
11764
|
+
// transparencyIndex - palette index of transparent color (-1 if there's none)
|
|
11765
|
+
function indexedToRgb(indexed, rgb, palette, transparencyIndex) {
|
|
11003
11766
|
const size = indexed.width * indexed.height;
|
|
11004
11767
|
const srcData = indexed.data;
|
|
11005
11768
|
const dstData = rgb.data;
|
|
11006
11769
|
for (let src = 0, dst = 0; src < size; src++, dst += 4) {
|
|
11007
|
-
const
|
|
11770
|
+
const index = srcData[src];
|
|
11771
|
+
const c = palette[index];
|
|
11008
11772
|
dstData[dst + 0] = c.r;
|
|
11009
11773
|
dstData[dst + 1] = c.g;
|
|
11010
11774
|
dstData[dst + 2] = c.b;
|
|
11011
|
-
dstData[dst + 3] = 255;
|
|
11775
|
+
dstData[dst + 3] = index === transparencyIndex ? 0 : 255;
|
|
11012
11776
|
}
|
|
11013
11777
|
}
|
|
11014
11778
|
// number of bytes used to store single channel value, 1-bit data is handled as bytes
|
|
@@ -11319,11 +12083,11 @@ function readColor(reader) {
|
|
|
11319
12083
|
skipBytes(reader, 2);
|
|
11320
12084
|
return { h, s, b };
|
|
11321
12085
|
}
|
|
11322
|
-
case 2 /* ColorSpace.CMYK */: {
|
|
11323
|
-
const c = readUint16(reader) / 257;
|
|
11324
|
-
const m = readUint16(reader) / 257;
|
|
11325
|
-
const y = readUint16(reader) / 257;
|
|
11326
|
-
const k = readUint16(reader) / 257;
|
|
12086
|
+
case 2 /* ColorSpace.CMYK */: { // 0 = 100% ink
|
|
12087
|
+
const c = (0xffff - readUint16(reader)) / 257;
|
|
12088
|
+
const m = (0xffff - readUint16(reader)) / 257;
|
|
12089
|
+
const y = (0xffff - readUint16(reader)) / 257;
|
|
12090
|
+
const k = (0xffff - readUint16(reader)) / 257;
|
|
11327
12091
|
return { c, m, y, k };
|
|
11328
12092
|
}
|
|
11329
12093
|
case 7 /* ColorSpace.Lab */: {
|
|
@@ -11344,6 +12108,24 @@ function readColor(reader) {
|
|
|
11344
12108
|
throw new Error('Invalid color space');
|
|
11345
12109
|
}
|
|
11346
12110
|
}
|
|
12111
|
+
const MAX_PATTERN_SIZE = 30000;
|
|
12112
|
+
// reads pattern, unsupported or invalid patterns are skipped (returns undefined) unless throwForMissingFeatures is set
|
|
12113
|
+
function readPatternSafe(reader) {
|
|
12114
|
+
let length = reader.view.getUint32(reader.offset);
|
|
12115
|
+
while (length % 4)
|
|
12116
|
+
length++;
|
|
12117
|
+
const end = reader.offset + 4 + length;
|
|
12118
|
+
try {
|
|
12119
|
+
return readPattern(reader);
|
|
12120
|
+
}
|
|
12121
|
+
catch (e) {
|
|
12122
|
+
if (reader.throwForMissingFeatures)
|
|
12123
|
+
throw e;
|
|
12124
|
+
reader.logMissingFeatures && reader.log(`Skipped pattern: ${e.message}`);
|
|
12125
|
+
reader.offset = end;
|
|
12126
|
+
return undefined;
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
11347
12129
|
function readPattern(reader) {
|
|
11348
12130
|
let length = readUint32(reader);
|
|
11349
12131
|
while (length % 4)
|
|
@@ -11355,8 +12137,8 @@ function readPattern(reader) {
|
|
|
11355
12137
|
const colorMode = readUint32(reader);
|
|
11356
12138
|
const x = readInt16(reader);
|
|
11357
12139
|
const y = readInt16(reader);
|
|
11358
|
-
// we only support RGB and
|
|
11359
|
-
if (colorMode !== 3 /* ColorMode.RGB */ && colorMode !== 1 /* ColorMode.Grayscale */ && colorMode !== 2 /* ColorMode.Indexed */) {
|
|
12140
|
+
// we only support RGB, grayscale, indexed and CMYK for now
|
|
12141
|
+
if (colorMode !== 3 /* ColorMode.RGB */ && colorMode !== 1 /* ColorMode.Grayscale */ && colorMode !== 2 /* ColorMode.Indexed */ && colorMode !== 4 /* ColorMode.CMYK */) {
|
|
11360
12142
|
throw new Error(`Unsupported pattern color mode: ${colorMode}`);
|
|
11361
12143
|
}
|
|
11362
12144
|
let name = readUnicodeString(reader);
|
|
@@ -11370,7 +12152,9 @@ function readPattern(reader) {
|
|
|
11370
12152
|
b: readUint8(reader),
|
|
11371
12153
|
});
|
|
11372
12154
|
}
|
|
11373
|
-
|
|
12155
|
+
// some writers follow the palette with 4 extra bytes (unknown)
|
|
12156
|
+
if (reader.view.getUint32(reader.offset) !== 3)
|
|
12157
|
+
skipBytes(reader, 4);
|
|
11374
12158
|
}
|
|
11375
12159
|
// virtual memory array list
|
|
11376
12160
|
const version2 = readUint32(reader);
|
|
@@ -11384,17 +12168,37 @@ function readPattern(reader) {
|
|
|
11384
12168
|
const channelsCount = readUint32(reader);
|
|
11385
12169
|
const width = right - left;
|
|
11386
12170
|
const height = bottom - top;
|
|
12171
|
+
if (width < 0 || height < 0)
|
|
12172
|
+
throw new Error('Invalid pattern bounds');
|
|
12173
|
+
if (width > MAX_PATTERN_SIZE || height > MAX_PATTERN_SIZE)
|
|
12174
|
+
throw new Error(`Pattern too large (${width}x${height})`);
|
|
12175
|
+
if (channelsCount > 64)
|
|
12176
|
+
throw new Error(`Invalid pattern channel count: ${channelsCount}`);
|
|
12177
|
+
// channels cover whole pattern, each 2 bytes of RLE data can produce at most 128 bytes
|
|
12178
|
+
if (width * height > (Math.min(end, reader.view.byteLength) - reader.offset) * 64)
|
|
12179
|
+
throw new Error('Pattern data out of bounds');
|
|
11387
12180
|
const size = width * height * 4;
|
|
11388
12181
|
consumeMemory(reader, size);
|
|
11389
12182
|
const data = new Uint8Array(size);
|
|
11390
12183
|
for (let i = 3; i < data.byteLength; i += 4) {
|
|
11391
12184
|
data[i] = 255;
|
|
11392
12185
|
}
|
|
11393
|
-
|
|
12186
|
+
// first written arrays are color channels, next one is transparency (Photoshop stores it in the last, sheet mask, array)
|
|
12187
|
+
const colorChannels = colorMode === 3 /* ColorMode.RGB */ ? 3 : (colorMode === 4 /* ColorMode.CMYK */ ? 4 : 1);
|
|
12188
|
+
// CMYK channels are decoded into separate buffer (5 values per pixel, inverted, 0 = 100% ink) and converted to RGB at the end
|
|
12189
|
+
const cmyk = colorMode === 4 /* ColorMode.CMYK */ ? new Uint8Array(width * height * 5).fill(255) : undefined;
|
|
12190
|
+
if (cmyk)
|
|
12191
|
+
consumeMemory(reader, cmyk.byteLength);
|
|
12192
|
+
const alphaTarget = cmyk ? 4 : 3;
|
|
12193
|
+
for (let i = 0, ch = 0; i < (channelsCount + 2) && reader.offset + 4 <= end; i++) {
|
|
11394
12194
|
const has = readUint32(reader);
|
|
11395
12195
|
if (!has)
|
|
11396
12196
|
continue;
|
|
11397
12197
|
const length = readUint32(reader);
|
|
12198
|
+
if (!length)
|
|
12199
|
+
continue;
|
|
12200
|
+
if (length < 23)
|
|
12201
|
+
throw new Error('Invalid pattern channel length');
|
|
11398
12202
|
const pixelDepth = readUint32(reader);
|
|
11399
12203
|
const ctop = readUint32(reader);
|
|
11400
12204
|
const cleft = readUint32(reader);
|
|
@@ -11402,97 +12206,92 @@ function readPattern(reader) {
|
|
|
11402
12206
|
const cright = readUint32(reader);
|
|
11403
12207
|
const pixelDepth2 = readUint16(reader);
|
|
11404
12208
|
const compressionMode = readUint8(reader); // 0 - raw, 1 - rle
|
|
11405
|
-
const
|
|
11406
|
-
const
|
|
11407
|
-
if (
|
|
11408
|
-
throw new Error(
|
|
11409
|
-
|
|
12209
|
+
const cdata = readBytes(reader, length - 23);
|
|
12210
|
+
const depth = (pixelDepth2 === 8 || pixelDepth2 === 16 || pixelDepth2 === 32) ? pixelDepth2 : pixelDepth;
|
|
12211
|
+
if (depth !== 8 && depth !== 16 && depth !== 32)
|
|
12212
|
+
throw new Error(`Unsupported pattern pixel depth: ${depth}`);
|
|
12213
|
+
if (ctop < top || cleft < left || cbottom > bottom || cright > right || cbottom < ctop || cright < cleft) {
|
|
12214
|
+
throw new Error('Pattern channel bounds outside of pattern bounds');
|
|
12215
|
+
}
|
|
12216
|
+
const target = ch < colorChannels ? ch : (ch === colorChannels ? alphaTarget : -1);
|
|
12217
|
+
ch++;
|
|
12218
|
+
if (target === -1)
|
|
12219
|
+
continue;
|
|
11410
12220
|
const w = cright - cleft;
|
|
11411
12221
|
const h = cbottom - ctop;
|
|
11412
|
-
const
|
|
11413
|
-
const
|
|
12222
|
+
const rowBytes = w * (depth / 8);
|
|
12223
|
+
const channelSize = rowBytes * h;
|
|
12224
|
+
let bytes;
|
|
11414
12225
|
if (compressionMode === 0) {
|
|
11415
|
-
if (
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
const src = x + y * w;
|
|
11419
|
-
const dst = (ox + x + (y + oy) * width) * 4;
|
|
11420
|
-
data[dst + ch] = cdata[src];
|
|
11421
|
-
}
|
|
11422
|
-
}
|
|
11423
|
-
}
|
|
11424
|
-
else if (colorMode === 1 /* ColorMode.Grayscale */ && ch < 1) {
|
|
11425
|
-
for (let y = 0; y < h; y++) {
|
|
11426
|
-
for (let x = 0; x < w; x++) {
|
|
11427
|
-
const src = x + y * w;
|
|
11428
|
-
const dst = (ox + x + (y + oy) * width) * 4;
|
|
11429
|
-
const value = cdata[src];
|
|
11430
|
-
data[dst + 0] = value;
|
|
11431
|
-
data[dst + 1] = value;
|
|
11432
|
-
data[dst + 2] = value;
|
|
11433
|
-
}
|
|
11434
|
-
}
|
|
11435
|
-
}
|
|
11436
|
-
else if (colorMode === 2 /* ColorMode.Indexed */) {
|
|
11437
|
-
for (let y = 0; y < h; y++) {
|
|
11438
|
-
for (let x = 0; x < w; x++) {
|
|
11439
|
-
const src = x + y * w;
|
|
11440
|
-
const dst = (ox + x + (y + oy) * width) * 4;
|
|
11441
|
-
const index = cdata[src];
|
|
11442
|
-
const color = palette[index];
|
|
11443
|
-
data[dst + 0] = color.r;
|
|
11444
|
-
data[dst + 1] = color.g;
|
|
11445
|
-
data[dst + 2] = color.b;
|
|
11446
|
-
}
|
|
11447
|
-
}
|
|
11448
|
-
}
|
|
11449
|
-
else {
|
|
11450
|
-
if (reader.throwForMissingFeatures)
|
|
11451
|
-
throw new Error('Invalid color pattern');
|
|
11452
|
-
}
|
|
12226
|
+
if (cdata.byteLength < channelSize)
|
|
12227
|
+
throw new Error('Pattern channel data out of bounds');
|
|
12228
|
+
bytes = cdata;
|
|
11453
12229
|
}
|
|
11454
12230
|
else if (compressionMode === 1) {
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
12231
|
+
// each 2 bytes of RLE data can produce at most 128 bytes
|
|
12232
|
+
if (channelSize > cdata.byteLength * 64)
|
|
12233
|
+
throw new Error('Pattern channel data out of bounds');
|
|
12234
|
+
consumeMemory(reader, channelSize);
|
|
12235
|
+
bytes = new Uint8Array(channelSize);
|
|
11458
12236
|
const cdataReader = createReader(cdata.buffer, cdata.byteOffset, cdata.byteLength);
|
|
11459
|
-
|
|
11460
|
-
readDataRLE(cdataReader, tempData, w, h, 8, 1, [0], false);
|
|
11461
|
-
copyChannelToRGBA(tempData, pixelData, ox, oy, ch);
|
|
11462
|
-
}
|
|
11463
|
-
if (colorMode === 1 /* ColorMode.Grayscale */ && ch < 1) {
|
|
11464
|
-
readDataRLE(cdataReader, tempData, w, h, 8, 1, [0], false);
|
|
11465
|
-
copyChannelToRGBA(tempData, pixelData, ox, oy, 0);
|
|
11466
|
-
setupGrayscale(pixelData);
|
|
11467
|
-
}
|
|
11468
|
-
if (colorMode === 2 /* ColorMode.Indexed */) {
|
|
11469
|
-
// TODO:
|
|
11470
|
-
throw new Error('Indexed pattern color mode not implemented');
|
|
11471
|
-
}
|
|
11472
|
-
recoverMemory(reader, w * h);
|
|
12237
|
+
readDataRLE(cdataReader, { data: bytes, width: rowBytes, height: h }, rowBytes, h, 8, 1, [0], false);
|
|
11473
12238
|
}
|
|
11474
12239
|
else {
|
|
11475
12240
|
throw new Error('Invalid pattern compression mode');
|
|
11476
12241
|
}
|
|
11477
|
-
|
|
12242
|
+
const ox = cleft - left;
|
|
12243
|
+
const oy = ctop - top;
|
|
12244
|
+
for (let y = 0; y < h; y++) {
|
|
12245
|
+
for (let x = 0; x < w; x++) {
|
|
12246
|
+
const src = x + y * w;
|
|
12247
|
+
const dst = (ox + x + (y + oy) * width) * 4;
|
|
12248
|
+
const value = depth === 8 ? bytes[src] : patternValueTo8bit(bytes, src, depth);
|
|
12249
|
+
if (cmyk) {
|
|
12250
|
+
cmyk[(ox + x + (y + oy) * width) * 5 + target] = value;
|
|
12251
|
+
}
|
|
12252
|
+
else if (target === 3) {
|
|
12253
|
+
data[dst + 3] = value;
|
|
12254
|
+
}
|
|
12255
|
+
else if (colorMode === 2 /* ColorMode.Indexed */) {
|
|
12256
|
+
const color = palette[value];
|
|
12257
|
+
data[dst + 0] = color.r;
|
|
12258
|
+
data[dst + 1] = color.g;
|
|
12259
|
+
data[dst + 2] = color.b;
|
|
12260
|
+
}
|
|
12261
|
+
else if (colorMode === 1 /* ColorMode.Grayscale */) {
|
|
12262
|
+
data[dst + 0] = value;
|
|
12263
|
+
data[dst + 1] = value;
|
|
12264
|
+
data[dst + 2] = value;
|
|
12265
|
+
}
|
|
12266
|
+
else {
|
|
12267
|
+
data[dst + target] = value;
|
|
12268
|
+
}
|
|
12269
|
+
}
|
|
12270
|
+
}
|
|
12271
|
+
if (compressionMode === 1)
|
|
12272
|
+
recoverMemory(reader, channelSize);
|
|
12273
|
+
}
|
|
12274
|
+
if (cmyk) {
|
|
12275
|
+
cmykToRgb({ width, height, data: cmyk }, { width, height, data }, false);
|
|
12276
|
+
recoverMemory(reader, cmyk.byteLength);
|
|
11478
12277
|
}
|
|
11479
12278
|
reader.offset = end;
|
|
11480
12279
|
return { id, name, x, y, bounds: { x: left, y: top, w: width, h: height }, data };
|
|
11481
12280
|
}
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
dstData.data[dst + offset] = value;
|
|
11492
|
-
}
|
|
12281
|
+
// converts big-endian 16bit or 32bit (float) value at given index to 8bit value
|
|
12282
|
+
function patternValueTo8bit(bytes, index, depth) {
|
|
12283
|
+
if (depth === 16) {
|
|
12284
|
+
return Math.round(((bytes[index * 2] << 8) | bytes[index * 2 + 1]) / 257);
|
|
12285
|
+
}
|
|
12286
|
+
else {
|
|
12287
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset + index * 4, 4);
|
|
12288
|
+
const value = view.getFloat32(0, false);
|
|
12289
|
+
return value > 0 ? (value < 1 ? Math.round(value * 255) : 255) : 0;
|
|
11493
12290
|
}
|
|
11494
12291
|
}
|
|
11495
12292
|
function consumeMemory(reader, size) {
|
|
12293
|
+
if (!(size >= 0))
|
|
12294
|
+
throw new Error('Invalid size');
|
|
11496
12295
|
if (reader.totalMemoryLimit !== undefined) {
|
|
11497
12296
|
if (reader.totalMemoryLimit < size)
|
|
11498
12297
|
throw new Error('Exceeded memory limit');
|
|
@@ -11505,7 +12304,7 @@ function recoverMemory(reader, size) {
|
|
|
11505
12304
|
}
|
|
11506
12305
|
}
|
|
11507
12306
|
|
|
11508
|
-
},{"./additionalInfo":2,"./helpers":8,"./imageResources":9,"pako":20}],14:[function(require,module,exports){
|
|
12307
|
+
},{"./additionalInfo":2,"./helpers":8,"./imageResources":9,"./utf8":16,"pako":20}],14:[function(require,module,exports){
|
|
11509
12308
|
"use strict";
|
|
11510
12309
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11511
12310
|
exports.createWriter = createWriter;
|
|
@@ -11540,11 +12339,12 @@ exports.writePattern = writePattern;
|
|
|
11540
12339
|
const helpers_1 = require("./helpers");
|
|
11541
12340
|
const additionalInfo_1 = require("./additionalInfo");
|
|
11542
12341
|
const imageResources_1 = require("./imageResources");
|
|
12342
|
+
const psdReader_1 = require("./psdReader");
|
|
11543
12343
|
function createWriter(size = 4096) {
|
|
11544
12344
|
const buffer = new ArrayBuffer(size);
|
|
11545
12345
|
const view = new DataView(buffer);
|
|
11546
12346
|
const offset = 0;
|
|
11547
|
-
return { buffer, view, offset, tempBuffer: undefined };
|
|
12347
|
+
return { buffer, view, offset, tempBuffer: undefined, log: console.log };
|
|
11548
12348
|
}
|
|
11549
12349
|
function getWriterBuffer(writer) {
|
|
11550
12350
|
return writer.buffer.slice(0, writer.offset);
|
|
@@ -11731,6 +12531,8 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11731
12531
|
const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
11732
12532
|
if (bitsPerChannel !== 8)
|
|
11733
12533
|
throw new Error('bitsPerChannel other than 8 are not supported for writing');
|
|
12534
|
+
if (options.log)
|
|
12535
|
+
writer.log = options.log;
|
|
11734
12536
|
const layers = [];
|
|
11735
12537
|
addChildren(layers, psd.children);
|
|
11736
12538
|
if (!layers.length)
|
|
@@ -11738,6 +12540,17 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11738
12540
|
verifyBitCount(psd);
|
|
11739
12541
|
const imageResources = Object.assign({}, psd.imageResources);
|
|
11740
12542
|
const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map() });
|
|
12543
|
+
// document is always written in RGB color mode, skip resources specific to original color mode
|
|
12544
|
+
if (psd.colorMode !== undefined && psd.colorMode !== 3 /* ColorMode.RGB */) {
|
|
12545
|
+
delete imageResources.iccProfile;
|
|
12546
|
+
delete imageResources.indexedColorCount;
|
|
12547
|
+
delete imageResources.transparencyIndex;
|
|
12548
|
+
delete imageResources.alphaChannelDisplayInfo;
|
|
12549
|
+
delete imageResources.colorHalftoneScreens;
|
|
12550
|
+
delete imageResources.grayscaleHalftoneScreens;
|
|
12551
|
+
delete imageResources.colorTransferFunctions;
|
|
12552
|
+
delete imageResources.grayscaleTransferFunctions;
|
|
12553
|
+
}
|
|
11741
12554
|
if (opt.generateThumbnail) {
|
|
11742
12555
|
imageResources.thumbnail = createThumbnail(psd);
|
|
11743
12556
|
}
|
|
@@ -11745,6 +12558,9 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11745
12558
|
if (!imageData && psd.canvas) {
|
|
11746
12559
|
imageData = psd.canvas.getContext('2d').getImageData(0, 0, psd.canvas.width, psd.canvas.height);
|
|
11747
12560
|
}
|
|
12561
|
+
if (!imageData && psd.rawCompositeData) { // read with `useRawData` option
|
|
12562
|
+
imageData = (0, psdReader_1.getCompositeImageData)(psd);
|
|
12563
|
+
}
|
|
11748
12564
|
if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
|
|
11749
12565
|
throw new Error('Document canvas must have the same size as document');
|
|
11750
12566
|
const globalAlpha = !!imageData && (0, helpers_1.hasAlpha)(imageData);
|
|
@@ -11759,19 +12575,8 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11759
12575
|
writeUint32(writer, psd.width);
|
|
11760
12576
|
writeUint16(writer, bitsPerChannel); // bits per channel
|
|
11761
12577
|
writeUint16(writer, 3 /* ColorMode.RGB */); // we only support saving RGB right now
|
|
11762
|
-
// color mode data
|
|
11763
|
-
|
|
11764
|
-
var _a, _b, _c;
|
|
11765
|
-
if (psd.palette) {
|
|
11766
|
-
for (let i = 0; i < 256; i++)
|
|
11767
|
-
writeUint8(writer, ((_a = psd.palette[i]) === null || _a === void 0 ? void 0 : _a.r) || 0);
|
|
11768
|
-
for (let i = 0; i < 256; i++)
|
|
11769
|
-
writeUint8(writer, ((_b = psd.palette[i]) === null || _b === void 0 ? void 0 : _b.g) || 0);
|
|
11770
|
-
for (let i = 0; i < 256; i++)
|
|
11771
|
-
writeUint8(writer, ((_c = psd.palette[i]) === null || _c === void 0 ? void 0 : _c.b) || 0);
|
|
11772
|
-
}
|
|
11773
|
-
// TODO: other data?
|
|
11774
|
-
});
|
|
12578
|
+
// color mode data (empty for RGB color mode)
|
|
12579
|
+
writeUint32(writer, 0);
|
|
11775
12580
|
// image resources
|
|
11776
12581
|
imageResources.layersGroup = layers.map(l => l.linkGroup || 0);
|
|
11777
12582
|
imageResources.layerGroupsEnabledId = layers.map(l => l.linkGroupEnabled == false ? 0 : 1);
|
|
@@ -11780,10 +12585,12 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11780
12585
|
const has = handler.has(imageResources);
|
|
11781
12586
|
const count = has === false ? 0 : (has === true ? 1 : has);
|
|
11782
12587
|
for (let i = 0; i < count; i++) {
|
|
12588
|
+
const id = handler.keyCount > 1 ? handler.key + i : handler.key;
|
|
12589
|
+
const name = handler.name ? handler.name(imageResources, i) : '';
|
|
11783
12590
|
writeSignature(writer, '8BIM');
|
|
11784
|
-
writeUint16(writer,
|
|
11785
|
-
writePascalString(writer,
|
|
11786
|
-
writeSection(writer, 2, () => handler.write(writer, imageResources, i));
|
|
12591
|
+
writeUint16(writer, id);
|
|
12592
|
+
writePascalString(writer, name, 2);
|
|
12593
|
+
writeSection(writer, 2, () => handler.write(writer, imageResources, i, psd));
|
|
11787
12594
|
}
|
|
11788
12595
|
}
|
|
11789
12596
|
});
|
|
@@ -11796,19 +12603,13 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11796
12603
|
writer.tempBuffer = undefined;
|
|
11797
12604
|
// image data
|
|
11798
12605
|
writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
|
|
11799
|
-
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
// encode directly into the writer buffer
|
|
11807
|
-
const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
|
|
11808
|
-
ensureSize(writer, writer.offset + maxSize);
|
|
11809
|
-
const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
|
|
11810
|
-
writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
|
|
11811
|
-
}
|
|
12606
|
+
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
12607
|
+
const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
|
|
12608
|
+
// encode directly into the writer buffer
|
|
12609
|
+
const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
|
|
12610
|
+
ensureSize(writer, writer.offset + maxSize);
|
|
12611
|
+
const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
|
|
12612
|
+
writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
|
|
11812
12613
|
}
|
|
11813
12614
|
function getCompositeData(imageData, width, height, globalAlpha) {
|
|
11814
12615
|
if (!imageData)
|
|
@@ -11837,7 +12638,7 @@ function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
|
11837
12638
|
writeSection(writer, 4, () => {
|
|
11838
12639
|
var _a;
|
|
11839
12640
|
writeInt16(writer, globalAlpha ? -layers.length : layers.length);
|
|
11840
|
-
const layersData = layers.map((l, i) => getChannels(writer
|
|
12641
|
+
const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
|
|
11841
12642
|
// layer records
|
|
11842
12643
|
for (const layerData of layersData) {
|
|
11843
12644
|
const { layer, top, left, bottom, right, channels } = layerData;
|
|
@@ -11889,7 +12690,12 @@ function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
|
11889
12690
|
}
|
|
11890
12691
|
}, true, options.psb);
|
|
11891
12692
|
}
|
|
11892
|
-
|
|
12693
|
+
// real mask is only stored separately if layer has both vector and pixel masks, otherwise it's stored as the main mask
|
|
12694
|
+
function getMasks(layer) {
|
|
12695
|
+
return layer.mask ? { mask: layer.mask, realMask: layer.realMask } : { mask: layer.realMask, realMask: undefined };
|
|
12696
|
+
}
|
|
12697
|
+
function writeLayerMaskData(writer, layer, layerData) {
|
|
12698
|
+
const { mask, realMask } = getMasks(layer);
|
|
11893
12699
|
writeSection(writer, 4, () => {
|
|
11894
12700
|
if (!mask && !realMask)
|
|
11895
12701
|
return;
|
|
@@ -11985,13 +12791,13 @@ function writeAdditionalLayerInfo(writer, target, psd, options) {
|
|
|
11985
12791
|
let key = handler.key;
|
|
11986
12792
|
if (key === 'Txt2' && options.invalidateTextLayers)
|
|
11987
12793
|
continue;
|
|
11988
|
-
if (key === 'vmsk' &&
|
|
11989
|
-
key = 'vsms';
|
|
12794
|
+
if (key === 'vmsk' && additionalInfo_1.infoHandlersMap['vscg'].has(target))
|
|
12795
|
+
key = 'vsms'; // Photoshop uses 'vsms' for layers with vector stroke
|
|
11990
12796
|
if (handler.has(target)) {
|
|
11991
12797
|
const large = options.psb && helpers_1.largeAdditionalInfoKeys.indexOf(key) !== -1;
|
|
11992
12798
|
const writeTotalLength = key !== 'Txt2' && key !== 'cinf' && key !== 'extn' && key !== 'CAI ' && key !== 'OCIO';
|
|
11993
12799
|
const fourBytes = key === 'levl' || key === 'Txt2' || key === 'luni' || key === 'vmsk' || key === 'artb' || key === 'artd' ||
|
|
11994
|
-
key === 'vogk' || key === 'SoLd' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
12800
|
+
key === 'vogk' || key === 'SoLd' || key === 'SoLE' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
11995
12801
|
key === 'lmfx' || key === 'lrFX' || key === 'cinf' || key === 'PlLd' || key === 'Anno' || key === 'CAI ' || key === 'OCIO' || key === 'GenI' || key === 'FEid' || key === 'curv' || key === 'CgEd' || key === 'vibA' || key === 'blwh' || key === 'grdm';
|
|
11996
12802
|
writeSignature(writer, large ? '8B64' : '8BIM');
|
|
11997
12803
|
writeSignature(writer, key);
|
|
@@ -12084,7 +12890,7 @@ function createThumbnail(psd) {
|
|
|
12084
12890
|
}
|
|
12085
12891
|
return canvas;
|
|
12086
12892
|
}
|
|
12087
|
-
function getMaskChannels(tempBuffer, layerData,
|
|
12893
|
+
function getMaskChannels(tempBuffer, layerData, mask, options, realMask) {
|
|
12088
12894
|
let top = mask.top | 0;
|
|
12089
12895
|
let left = mask.left | 0;
|
|
12090
12896
|
let right = mask.right | 0;
|
|
@@ -12101,11 +12907,7 @@ function getMaskChannels(tempBuffer, layerData, layer, mask, options, realMask)
|
|
|
12101
12907
|
bottom = top + height;
|
|
12102
12908
|
let buffer;
|
|
12103
12909
|
let compression;
|
|
12104
|
-
if (
|
|
12105
|
-
buffer = layer[realMask ? 'realMaskDataRaw' : 'maskDataRaw'];
|
|
12106
|
-
compression = layer[realMask ? 'realMaskDataRawCompression' : 'maskDataRawCompression'];
|
|
12107
|
-
}
|
|
12108
|
-
else if (!imageData) {
|
|
12910
|
+
if (!imageData) {
|
|
12109
12911
|
buffer = new Uint8Array(0);
|
|
12110
12912
|
compression = 1 /* Compression.RleCompressed */;
|
|
12111
12913
|
}
|
|
@@ -12128,15 +12930,32 @@ function bounds(obj) {
|
|
|
12128
12930
|
bottom: obj.bottom || 0,
|
|
12129
12931
|
} : undefined;
|
|
12130
12932
|
}
|
|
12131
|
-
function getChannels(
|
|
12933
|
+
function getChannels(writer, layer, background, options) {
|
|
12934
|
+
let source = layer;
|
|
12132
12935
|
if (layer.rawData) {
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12936
|
+
const { colorMode, bitsPerChannel, large } = layer.rawData;
|
|
12937
|
+
if (large === !!options.psb && colorMode === 3 /* ColorMode.RGB */ && bitsPerChannel === 8) {
|
|
12938
|
+
// same mask mapping as in writeLayerMaskData
|
|
12939
|
+
const { mask, realMask } = getMasks(layer);
|
|
12940
|
+
return Object.assign(Object.assign({ layer, channels: layer.rawData.channels.map(c => { var _a, _b; return (Object.assign(Object.assign({}, c), { length: 2 + ((_b = (_a = c.data) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : 0) })); }) }, bounds(layer)), { mask: bounds(mask), realMask: bounds(realMask) });
|
|
12941
|
+
}
|
|
12942
|
+
if (bitsPerChannel !== 8)
|
|
12943
|
+
throw new Error('Layer raw data with bitsPerChannel other than 8 is not supported for writing');
|
|
12944
|
+
// raw data is in different format than the one we're writing, decode it so it can be re-encoded
|
|
12945
|
+
source = Object.assign(Object.assign({}, layer), { rawData: undefined, canvas: undefined, imageData: (0, psdReader_1.getLayerImageData)(layer), mask: layer.mask && Object.assign(Object.assign({}, layer.mask), { canvas: undefined, imageData: (0, psdReader_1.getLayerMaskImageData)(layer) }), realMask: layer.realMask && Object.assign(Object.assign({}, layer.realMask), { canvas: undefined, imageData: (0, psdReader_1.getLayerRealMaskImageData)(layer) }) });
|
|
12946
|
+
// temp buffer is sized only for layers with image data, grow it and keep it for following layers
|
|
12947
|
+
const size = getLargestLayerSize([Object.assign(Object.assign({}, source), { children: undefined })], !!options.psb);
|
|
12948
|
+
if (writer.tempBuffer.byteLength < size)
|
|
12949
|
+
writer.tempBuffer = new Uint8Array(size);
|
|
12950
|
+
}
|
|
12951
|
+
const tempBuffer = writer.tempBuffer;
|
|
12952
|
+
const { mask, realMask } = getMasks(source);
|
|
12953
|
+
const layerData = getLayerChannels(tempBuffer, source, background, options);
|
|
12954
|
+
if (mask)
|
|
12955
|
+
getMaskChannels(tempBuffer, layerData, mask, options, false);
|
|
12956
|
+
if (realMask)
|
|
12957
|
+
getMaskChannels(tempBuffer, layerData, realMask, options, true);
|
|
12958
|
+
layerData.layer = layer;
|
|
12140
12959
|
return layerData;
|
|
12141
12960
|
}
|
|
12142
12961
|
function getLayerDimentions({ canvas, imageData }) {
|
|
@@ -12166,7 +12985,6 @@ function cropImageData(data, left, top, width, height) {
|
|
|
12166
12985
|
return croppedData;
|
|
12167
12986
|
}
|
|
12168
12987
|
function getLayerChannels(tempBuffer, layer, background, options) {
|
|
12169
|
-
var _a;
|
|
12170
12988
|
let top = layer.top | 0;
|
|
12171
12989
|
let left = layer.left | 0;
|
|
12172
12990
|
let right = layer.right | 0;
|
|
@@ -12205,19 +13023,14 @@ function getLayerChannels(tempBuffer, layer, background, options) {
|
|
|
12205
13023
|
1 /* ChannelID.Color1 */,
|
|
12206
13024
|
2 /* ChannelID.Color2 */,
|
|
12207
13025
|
];
|
|
12208
|
-
if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)
|
|
13026
|
+
if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)) {
|
|
12209
13027
|
channelIds.unshift(-1 /* ChannelID.Transparency */);
|
|
12210
13028
|
}
|
|
12211
13029
|
channels = channelIds.map(id => {
|
|
12212
|
-
const offset = (0, helpers_1.offsetForChannel)(id, false); //
|
|
13030
|
+
const offset = (0, helpers_1.offsetForChannel)(id, false); // image data is always RGBA
|
|
12213
13031
|
let data;
|
|
12214
13032
|
let compression;
|
|
12215
|
-
if (
|
|
12216
|
-
// console.log('written raw layer image data');
|
|
12217
|
-
data = layer.imageDataRaw[id];
|
|
12218
|
-
compression = layer.imageDataRawCompression[id];
|
|
12219
|
-
}
|
|
12220
|
-
else if (options.compress) {
|
|
13033
|
+
if (options.compress) {
|
|
12221
13034
|
data = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [offset]);
|
|
12222
13035
|
compression = 2 /* Compression.ZipWithoutPrediction */;
|
|
12223
13036
|
}
|
|
@@ -12298,11 +13111,12 @@ function writeColor(writer, color) {
|
|
|
12298
13111
|
writeUint16(writer, 0);
|
|
12299
13112
|
}
|
|
12300
13113
|
else if ('c' in color) {
|
|
13114
|
+
// 0 = 100% ink
|
|
12301
13115
|
writeUint16(writer, 2 /* ColorSpace.CMYK */);
|
|
12302
|
-
writeUint16(writer, Math.round(color.c * 257));
|
|
12303
|
-
writeUint16(writer, Math.round(color.m * 257));
|
|
12304
|
-
writeUint16(writer, Math.round(color.y * 257));
|
|
12305
|
-
writeUint16(writer, Math.round(color.k * 257));
|
|
13116
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.c, 0, 255) * 257));
|
|
13117
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.m, 0, 255) * 257));
|
|
13118
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.y, 0, 255) * 257));
|
|
13119
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.k, 0, 255) * 257));
|
|
12306
13120
|
}
|
|
12307
13121
|
else {
|
|
12308
13122
|
writeUint16(writer, 8 /* ColorSpace.Grayscale */);
|
|
@@ -12369,7 +13183,7 @@ function writePattern(writer, pattern) {
|
|
|
12369
13183
|
writer.view.setUint32(pattsOffset - 4, pattsLength, false);
|
|
12370
13184
|
}
|
|
12371
13185
|
|
|
12372
|
-
},{"./additionalInfo":2,"./helpers":8,"./imageResources":9}],15:[function(require,module,exports){
|
|
13186
|
+
},{"./additionalInfo":2,"./helpers":8,"./imageResources":9,"./psdReader":13}],15:[function(require,module,exports){
|
|
12373
13187
|
"use strict";
|
|
12374
13188
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12375
13189
|
exports.decodeEngineData = decodeEngineData;
|
|
@@ -12463,7 +13277,16 @@ const styleKeys = [
|
|
|
12463
13277
|
'strokeFlag', 'fillFirst', 'yUnderline', 'outlineWidth', 'characterDirection', 'hindiNumbers',
|
|
12464
13278
|
'kashida', 'diacriticPos',
|
|
12465
13279
|
];
|
|
12466
|
-
const antialias = [
|
|
13280
|
+
const antialias = [
|
|
13281
|
+
'none', // 0
|
|
13282
|
+
'crisp', // 1
|
|
13283
|
+
'strong', // 2
|
|
13284
|
+
'smooth', // 3
|
|
13285
|
+
'sharp', // 4
|
|
13286
|
+
undefined, // 5 - unknown
|
|
13287
|
+
'platformLCD', // 6
|
|
13288
|
+
'platform', // 7
|
|
13289
|
+
];
|
|
12467
13290
|
const justification = [
|
|
12468
13291
|
'left', // 0
|
|
12469
13292
|
'right', // 1
|
|
@@ -12556,8 +13379,9 @@ function objectsEqual(a, b) {
|
|
|
12556
13379
|
return true;
|
|
12557
13380
|
}
|
|
12558
13381
|
function findOrAddFont(fonts, font) {
|
|
13382
|
+
// Photoshop writes separate entries for the same font with different synthetic (faux bold/italic) styles
|
|
12559
13383
|
for (let i = 0; i < fonts.length; i++) {
|
|
12560
|
-
if (fonts[i].name === font.name)
|
|
13384
|
+
if (fonts[i].name === font.name && (fonts[i].synthetic || 0) === (font.synthetic || 0))
|
|
12561
13385
|
return i;
|
|
12562
13386
|
}
|
|
12563
13387
|
fonts.push(font);
|
|
@@ -12753,7 +13577,8 @@ function decodeEngineData(engineData) {
|
|
|
12753
13577
|
result.paragraphStyleRuns.push({ length, style /*, adjustments*/ });
|
|
12754
13578
|
}
|
|
12755
13579
|
for (let counter = removedCharacters; result.paragraphStyleRuns.length && counter > 0; counter--) {
|
|
12756
|
-
|
|
13580
|
+
// keep 0 length run if it's for empty last paragraph, otherwise we lose its style
|
|
13581
|
+
if (--result.paragraphStyleRuns[result.paragraphStyleRuns.length - 1].length === 0 && result.paragraphStyleRuns.length === 1) {
|
|
12757
13582
|
result.paragraphStyleRuns.pop();
|
|
12758
13583
|
}
|
|
12759
13584
|
}
|
|
@@ -12829,13 +13654,13 @@ function encodeEngineData(data) {
|
|
|
12829
13654
|
for (const run of paragraphRuns) {
|
|
12830
13655
|
let runLength = Math.min(run.length, leftLength);
|
|
12831
13656
|
leftLength -= runLength;
|
|
12832
|
-
if (
|
|
12833
|
-
continue; // ignore 0 size runs
|
|
12834
|
-
// extend last run if it's only for trailing \r
|
|
13657
|
+
// extend last run if it's only for trailing \r (last run has 0 length if it's for empty last paragraph)
|
|
12835
13658
|
if (leftLength === 1 && run === paragraphRuns[paragraphRuns.length - 1]) {
|
|
12836
13659
|
runLength++;
|
|
12837
13660
|
leftLength--;
|
|
12838
13661
|
}
|
|
13662
|
+
if (!runLength)
|
|
13663
|
+
continue; // ignore 0 size runs
|
|
12839
13664
|
paragraphRunLengthArray.push(runLength);
|
|
12840
13665
|
paragraphRunArray.push({
|
|
12841
13666
|
ParagraphSheet: {
|
|
@@ -13138,9 +13963,6 @@ function encodeString(value) {
|
|
|
13138
13963
|
// UTF-8 decoder implementing the WHATWG Encoding Standard's non-fatal error handling,
|
|
13139
13964
|
// so malformed byte sequences are replaced with U+FFFD instead of throwing, matching TextDecoder.
|
|
13140
13965
|
function decodeString(value) {
|
|
13141
|
-
if (value.byteLength > 1000 && typeof TextDecoder !== 'undefined') {
|
|
13142
|
-
return (new TextDecoder()).decode(value);
|
|
13143
|
-
}
|
|
13144
13966
|
const result = [];
|
|
13145
13967
|
function pushCodePoint(code) {
|
|
13146
13968
|
if (code > 0xffff) {
|