ag-psd 31.0.3 → 32.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.v8-cache/v24.7.0-x64-ef5a0af0/00d0e0b4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/0cc76730 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/20729831 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/214a593b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/25f8b84a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/27518289 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/330ef2d9 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/37ff16b8 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/3f72a97c +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/75efccd4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/762f9305 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7bcfc50a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/825e9a05 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87372817 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/891a7c73 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/8b68a3a2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a1d12a93 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a7e80865 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/ac317c9c +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b8569d6b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b8b073c4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/bb489c89 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c46725e1 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c794cb34 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cd4ae980 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/d02dd6f7 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6735171 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f5417276 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f74d3518 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f886deac +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fd0a2987 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fe349423 +0 -0
- package/CHANGELOG.md +29 -0
- package/dist/abr.js +12 -5
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +2 -0
- package/dist/additionalInfo.js +123 -68
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +1365 -632
- package/dist/descriptor.d.ts +15 -2
- package/dist/descriptor.js +329 -100
- package/dist/descriptor.js.map +1 -1
- package/dist/effectsHelpers.js +12 -12
- package/dist/effectsHelpers.js.map +1 -1
- package/dist/engineData.d.ts +3 -1
- package/dist/engineData.js +34 -13
- package/dist/engineData.js.map +1 -1
- package/dist/engineData2.js +50 -21
- package/dist/engineData2.js.map +1 -1
- package/dist/helpers.d.ts +5 -2
- package/dist/helpers.js +18 -4
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +45 -21
- package/dist/imageResources.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jpeg.js +27 -7
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +6 -1
- package/dist/psdReader.d.ts +2 -2
- package/dist/psdReader.js +457 -270
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +2 -0
- package/dist/psdWriter.js +98 -76
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.js +126 -23
- package/dist/text.js.map +1 -1
- package/dist/utf8.js +36 -15
- package/dist/utf8.js.map +1 -1
- package/dist-es/abr.js +12 -5
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +2 -0
- package/dist-es/additionalInfo.js +123 -68
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/descriptor.d.ts +15 -2
- package/dist-es/descriptor.js +329 -100
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/effectsHelpers.js +12 -12
- package/dist-es/effectsHelpers.js.map +1 -1
- package/dist-es/engineData.d.ts +3 -1
- package/dist-es/engineData.js +34 -13
- package/dist-es/engineData.js.map +1 -1
- package/dist-es/engineData2.js +50 -21
- package/dist-es/engineData2.js.map +1 -1
- package/dist-es/helpers.d.ts +5 -2
- package/dist-es/helpers.js +18 -4
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +45 -21
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/index.js +1 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/jpeg.js +27 -7
- package/dist-es/jpeg.js.map +1 -1
- package/dist-es/psd.d.ts +6 -1
- package/dist-es/psdReader.d.ts +2 -2
- package/dist-es/psdReader.js +457 -270
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +2 -0
- package/dist-es/psdWriter.js +98 -76
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.js +126 -23
- package/dist-es/text.js.map +1 -1
- package/dist-es/utf8.js +36 -15
- package/dist-es/utf8.js.map +1 -1
- package/package.json +1 -1
- package/src/abr.ts +14 -6
- package/src/additionalInfo.ts +127 -66
- package/src/descriptor.ts +347 -107
- package/src/effectsHelpers.ts +9 -9
- package/src/engineData.ts +36 -13
- package/src/engineData2.ts +468 -432
- package/src/helpers.ts +19 -4
- package/src/imageResources.ts +49 -22
- package/src/index.ts +1 -0
- package/src/jpeg.ts +24 -9
- package/src/psd.ts +3 -1
- package/src/psdReader.ts +477 -260
- package/src/psdWriter.ts +100 -83
- package/src/text.ts +122 -12
- package/src/utf8.ts +35 -17
package/dist/bundle.js
CHANGED
|
@@ -7,6 +7,8 @@ const psdReader_1 = require("./psdReader");
|
|
|
7
7
|
const dynamicsControl = ['off', 'fade', 'pen pressure', 'pen tilt', 'stylus wheel', 'initial direction', 'direction', 'initial rotation', 'rotation'];
|
|
8
8
|
const dynamicBrushShapeShapes = ['round point', 'round blunt', 'round curve', 'round angle', 'round fan', 'flat point', 'flat blunt', 'flat curve', 'flat angle', 'flat fan'];
|
|
9
9
|
const tipsBrushShapeShapes = ['erodible point', 'erodible flat', 'erodible round', 'erodible square', 'erodible triangle', 'custom'];
|
|
10
|
+
// sanity limits for brush sample dimensions (Photoshop brushes are limited to 5000px)
|
|
11
|
+
const MAX_BRUSH_SIZE = 10000;
|
|
10
12
|
const toBrushType = {
|
|
11
13
|
_: 'brush',
|
|
12
14
|
MixB: 'mixer brush',
|
|
@@ -113,7 +115,7 @@ function readAbr(buffer, options = {}) {
|
|
|
113
115
|
while (reader.offset < reader.view.byteLength) {
|
|
114
116
|
(0, psdReader_1.checkSignature)(reader, '8BIM');
|
|
115
117
|
const type = (0, psdReader_1.readSignature)(reader);
|
|
116
|
-
|
|
118
|
+
const size = (0, psdReader_1.readUint32)(reader);
|
|
117
119
|
const end = reader.offset + size;
|
|
118
120
|
switch (type) {
|
|
119
121
|
case 'samp': {
|
|
@@ -132,8 +134,14 @@ function readAbr(buffer, options = {}) {
|
|
|
132
134
|
const w = (0, psdReader_1.readInt32)(reader) - x;
|
|
133
135
|
if (w <= 0 || h <= 0)
|
|
134
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
|
+
}
|
|
135
140
|
const bithDepth = (0, psdReader_1.readInt16)(reader);
|
|
136
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
|
+
}
|
|
137
145
|
const alpha = new Uint8Array(w * h);
|
|
138
146
|
if (bithDepth === 8) {
|
|
139
147
|
if (compression === 0) {
|
|
@@ -347,11 +355,10 @@ function readAbr(buffer, options = {}) {
|
|
|
347
355
|
default:
|
|
348
356
|
throw new Error(`Invalid brush type: ${type}`);
|
|
349
357
|
}
|
|
350
|
-
// align to 4 bytes
|
|
351
|
-
|
|
358
|
+
// skip any unread data in the section and align to 4 bytes
|
|
359
|
+
reader.offset = end;
|
|
360
|
+
while (reader.offset % 4)
|
|
352
361
|
reader.offset++;
|
|
353
|
-
size++;
|
|
354
|
-
}
|
|
355
362
|
}
|
|
356
363
|
}
|
|
357
364
|
else {
|
|
@@ -395,10 +402,6 @@ function readLength64(reader) {
|
|
|
395
402
|
throw new Error(`Resource size above 4 GB limit at ${reader.offset.toString(16)}`);
|
|
396
403
|
return (0, psdReader_1.readUint32)(reader);
|
|
397
404
|
}
|
|
398
|
-
function writeLength64(writer, length) {
|
|
399
|
-
(0, psdWriter_1.writeUint32)(writer, 0);
|
|
400
|
-
(0, psdWriter_1.writeUint32)(writer, length);
|
|
401
|
-
}
|
|
402
405
|
addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
403
406
|
if ((0, psdReader_1.readInt16)(reader) !== 1)
|
|
404
407
|
throw new Error(`Invalid TySh version`);
|
|
@@ -437,7 +440,7 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
|
437
440
|
if (text.boundingBox)
|
|
438
441
|
target.text.boundingBox = (0, descriptor_1.descBoundsToBounds)(text.boundingBox);
|
|
439
442
|
if (text.EngineData) {
|
|
440
|
-
const engineData = (0, engineData_1.parseEngineData)(text.EngineData);
|
|
443
|
+
const engineData = (0, engineData_1.parseEngineData)(text.EngineData, reader);
|
|
441
444
|
const textData = (0, text_1.decodeEngineData)(engineData);
|
|
442
445
|
// console.log(require('util').inspect(engineData, false, 99, false), 'utf8');
|
|
443
446
|
// require('fs').writeFileSync(`layer-${target.name}.txt`, require('util').inspect(engineData, false, 99, false), 'utf8');
|
|
@@ -451,6 +454,7 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
|
451
454
|
}
|
|
452
455
|
(0, psdReader_1.skipBytes)(reader, leftBytes());
|
|
453
456
|
}, (writer, target) => {
|
|
457
|
+
var _a, _b, _c, _d;
|
|
454
458
|
const text = target.text;
|
|
455
459
|
const warp = text.warp || {};
|
|
456
460
|
const transform = text.transform || [1, 0, 0, 1, 0, 0];
|
|
@@ -463,10 +467,10 @@ addHandler('TySh', hasKey('text'), (reader, target, leftBytes) => {
|
|
|
463
467
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'TxLr', textDescriptor, 'text');
|
|
464
468
|
(0, psdWriter_1.writeInt16)(writer, 1); // warp version
|
|
465
469
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'warp', encodeWarp(warp));
|
|
466
|
-
(0, psdWriter_1.writeFloat32)(writer, text.left);
|
|
467
|
-
(0, psdWriter_1.writeFloat32)(writer, text.top);
|
|
468
|
-
(0, psdWriter_1.writeFloat32)(writer, text.right);
|
|
469
|
-
(0, psdWriter_1.writeFloat32)(writer, text.bottom);
|
|
470
|
+
(0, psdWriter_1.writeFloat32)(writer, (_a = text.left) !== null && _a !== void 0 ? _a : 0);
|
|
471
|
+
(0, psdWriter_1.writeFloat32)(writer, (_b = text.top) !== null && _b !== void 0 ? _b : 0);
|
|
472
|
+
(0, psdWriter_1.writeFloat32)(writer, (_c = text.right) !== null && _c !== void 0 ? _c : 0);
|
|
473
|
+
(0, psdWriter_1.writeFloat32)(writer, (_d = text.bottom) !== null && _d !== void 0 ? _d : 0);
|
|
470
474
|
// writeZeros(writer, 2);
|
|
471
475
|
});
|
|
472
476
|
// vector fills
|
|
@@ -782,12 +786,50 @@ addHandler('luni', hasKey('name'), (reader, target, left) => {
|
|
|
782
786
|
// writeUint16(writer, 0); // padding (but not extending string length)
|
|
783
787
|
});
|
|
784
788
|
addHandler('lnsr', hasKey('nameSource'), (reader, target) => target.nameSource = (0, psdReader_1.readSignature)(reader), (writer, target) => (0, psdWriter_1.writeSignature)(writer, target.nameSource));
|
|
785
|
-
|
|
789
|
+
// these sections reference layer id
|
|
790
|
+
function layerNeedsId(target) {
|
|
791
|
+
return !!(target.animationFrames || target.timeline || target.comps);
|
|
792
|
+
}
|
|
793
|
+
function getExplicitLayerIds(psd, options) {
|
|
794
|
+
if (!options.explicitLayerIds) {
|
|
795
|
+
const ids = new Set();
|
|
796
|
+
const addIds = (layers) => {
|
|
797
|
+
for (const layer of layers !== null && layers !== void 0 ? layers : []) {
|
|
798
|
+
if (layer.id !== undefined)
|
|
799
|
+
ids.add(layer.id);
|
|
800
|
+
addIds(layer.children);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
addIds(psd.children);
|
|
804
|
+
options.explicitLayerIds = ids;
|
|
805
|
+
}
|
|
806
|
+
return options.explicitLayerIds;
|
|
807
|
+
}
|
|
808
|
+
function getLayerId(target, options) {
|
|
809
|
+
var _a;
|
|
810
|
+
const id = (_a = options.layerToId.get(target)) !== null && _a !== void 0 ? _a : target.id;
|
|
811
|
+
if (id === undefined)
|
|
812
|
+
throw new Error('Missing layer id');
|
|
813
|
+
return id;
|
|
814
|
+
}
|
|
815
|
+
addHandler('lyid', target => target.id !== undefined || layerNeedsId(target), (reader, target) => {
|
|
786
816
|
target.id = (0, psdReader_1.readUint32)(reader);
|
|
787
|
-
}, (writer, target,
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
817
|
+
}, (writer, target, psd, options) => {
|
|
818
|
+
var _a;
|
|
819
|
+
let id;
|
|
820
|
+
if (target.id !== undefined) {
|
|
821
|
+
id = target.id;
|
|
822
|
+
while (options.layerIds.has(id))
|
|
823
|
+
id += 100; // make sure we don't have duplicate layer ids
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
// generate id for layers that don't have it, if it's referenced by other sections
|
|
827
|
+
const explicitIds = getExplicitLayerIds(psd, options);
|
|
828
|
+
id = (_a = options.nextGeneratedLayerId) !== null && _a !== void 0 ? _a : 1;
|
|
829
|
+
while (options.layerIds.has(id) || explicitIds.has(id))
|
|
830
|
+
id++;
|
|
831
|
+
options.nextGeneratedLayerId = id + 1;
|
|
832
|
+
}
|
|
791
833
|
(0, psdWriter_1.writeUint32)(writer, id);
|
|
792
834
|
options.layerIds.add(id);
|
|
793
835
|
options.layerToId.set(target, id);
|
|
@@ -985,9 +1027,8 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
985
1027
|
(0, psdWriter_1.writeUint8)(writer, 0); // copy (always false)
|
|
986
1028
|
(0, psdWriter_1.writeZeros)(writer, 3);
|
|
987
1029
|
(0, psdWriter_1.writeSection)(writer, 2, () => {
|
|
988
|
-
var _a;
|
|
989
1030
|
const desc = {
|
|
990
|
-
LaID: (
|
|
1031
|
+
LaID: getLayerId(target, options),
|
|
991
1032
|
LaSt: [],
|
|
992
1033
|
};
|
|
993
1034
|
for (let i = 0; i < animationFrames.length; i++) {
|
|
@@ -1043,10 +1084,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1043
1084
|
if (timeline.tracks) {
|
|
1044
1085
|
desc.trackList = (0, descriptor_1.serializeTrackList)(timeline.tracks);
|
|
1045
1086
|
}
|
|
1046
|
-
|
|
1047
|
-
if (!id)
|
|
1048
|
-
throw new Error('You need to provide layer.id value whan writing document with animations');
|
|
1049
|
-
desc.LyrI = id;
|
|
1087
|
+
desc.LyrI = getLayerId(target, options);
|
|
1050
1088
|
// console.log('WRITE:tmln', target.name, target.id, require('util').inspect(desc, false, 99, true));
|
|
1051
1089
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc, 'anim');
|
|
1052
1090
|
}, true);
|
|
@@ -1069,14 +1107,11 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1069
1107
|
(0, psdWriter_1.writeUint8)(writer, 0); // copy (always false)
|
|
1070
1108
|
(0, psdWriter_1.writeZeros)(writer, 3);
|
|
1071
1109
|
(0, psdWriter_1.writeSection)(writer, 2, () => {
|
|
1072
|
-
const id = options.layerToId.get(target) || target.id;
|
|
1073
|
-
if (!id)
|
|
1074
|
-
throw new Error('You need to provide layer.id value whan writing document with layer comps');
|
|
1075
1110
|
const desc = {};
|
|
1076
1111
|
if (comps.originalEffectsReferencePoint) {
|
|
1077
1112
|
desc.origFXRefPoint = { Hrzn: comps.originalEffectsReferencePoint.x, Vrtc: comps.originalEffectsReferencePoint.y };
|
|
1078
1113
|
}
|
|
1079
|
-
desc.LyrI =
|
|
1114
|
+
desc.LyrI = getLayerId(target, options);
|
|
1080
1115
|
desc.layerSettings = [];
|
|
1081
1116
|
for (const item of comps.settings) {
|
|
1082
1117
|
const t = {};
|
|
@@ -1094,7 +1129,7 @@ target => target.timestamp !== undefined || target.animationFrames !== undefined
|
|
|
1094
1129
|
}, true);
|
|
1095
1130
|
}
|
|
1096
1131
|
});
|
|
1097
|
-
addHandler('PxSc', ()
|
|
1132
|
+
addHandler('PxSc', hasKey('pixelSource'), (reader, target) => {
|
|
1098
1133
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
|
|
1099
1134
|
// console.log('PxSc', require('util').inspect(desc, false, 99, true));
|
|
1100
1135
|
if (desc.pixelSourceType === 1986285651) {
|
|
@@ -1129,7 +1164,7 @@ addHandler('PxSc', () => false, (reader, target) => {
|
|
|
1129
1164
|
_classID: 'PixelSource',
|
|
1130
1165
|
pixelSourceType: 1986285651, // vdP
|
|
1131
1166
|
descVersion: 1,
|
|
1132
|
-
origin: { Hrzn: source.origin.x, Vrtc: source.origin.y },
|
|
1167
|
+
origin: { Hrzn: source.origin.x, Vrtc: source.origin.y }, // written as 'null' class with 'long' values (see writeDescriptorStructure)
|
|
1133
1168
|
interpretation: {
|
|
1134
1169
|
_name: '',
|
|
1135
1170
|
_classID: 'footageInterpretation',
|
|
@@ -1371,10 +1406,12 @@ addHandler('PlLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
1371
1406
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', type, encodeWarp(warp), type);
|
|
1372
1407
|
});
|
|
1373
1408
|
function uint8ToFloat32(array) {
|
|
1374
|
-
|
|
1409
|
+
const length = Math.floor(array.byteLength / 4);
|
|
1410
|
+
return new Float32Array(array.buffer.slice(array.byteOffset, array.byteOffset + length * 4), 0, length);
|
|
1375
1411
|
}
|
|
1376
1412
|
function uint8ToUint32(array) {
|
|
1377
|
-
|
|
1413
|
+
const length = Math.floor(array.byteLength / 4);
|
|
1414
|
+
return new Uint32Array(array.buffer.slice(array.byteOffset, array.byteOffset + length * 4), 0, length);
|
|
1378
1415
|
}
|
|
1379
1416
|
function toUint8(array) {
|
|
1380
1417
|
return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
@@ -1643,7 +1680,7 @@ function parseFilterFXItem(f, options) {
|
|
|
1643
1680
|
{ x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
|
|
1644
1681
|
{ x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
|
|
1645
1682
|
],
|
|
1646
|
-
puppetShapeList: f.Fltr.puppetShapeList.map(p => ({
|
|
1683
|
+
puppetShapeList: (f.Fltr.puppetShapeList || []).map(p => ({
|
|
1647
1684
|
rigidType: p.rigidType,
|
|
1648
1685
|
// TODO: VrsM
|
|
1649
1686
|
// TODO: VrsN
|
|
@@ -2172,7 +2209,7 @@ function serializeFilterFXItem(f) {
|
|
|
2172
2209
|
_classID: 'rigidTransform',
|
|
2173
2210
|
'null': ['Ordn.Trgt'], // TODO: ???
|
|
2174
2211
|
rigidType: f.filter.rigidType,
|
|
2175
|
-
puppetShapeList: f.filter.puppetShapeList.map(p => ({
|
|
2212
|
+
puppetShapeList: (f.filter.puppetShapeList || []).map(p => ({
|
|
2176
2213
|
_name: '',
|
|
2177
2214
|
_classID: 'puppetShape',
|
|
2178
2215
|
rigidType: p.rigidType,
|
|
@@ -2257,7 +2294,7 @@ function serializeFilterFXItem(f) {
|
|
|
2257
2294
|
_classID: 'perspectiveWarpTransform',
|
|
2258
2295
|
vertices: f.filter.vertices.map(pointToHrznVrtc),
|
|
2259
2296
|
warpedVertices: f.filter.warpedVertices.map(pointToHrznVrtc),
|
|
2260
|
-
quads: f.filter.quads.map(indices => ({ indices })),
|
|
2297
|
+
quads: f.filter.quads.map(indices => ({ _name: '', _classID: 'quadIndices', indices })),
|
|
2261
2298
|
}, filterID: 442 });
|
|
2262
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 ? {
|
|
2263
2300
|
Adjs: f.filter.adjustments.map(a => 'curve' in a ? {
|
|
@@ -2279,10 +2316,13 @@ function serializeFilterFXItem(f) {
|
|
|
2279
2316
|
Cntr: f.filter.contrast,
|
|
2280
2317
|
useLegacy: !!f.filter.useLegacy,
|
|
2281
2318
|
}, filterID: 1114793795 });
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2319
|
+
case 'hsb/hsl': return Object.assign(Object.assign({}, base), { Fltr: {
|
|
2320
|
+
_name: 'HSB/HSL',
|
|
2321
|
+
_classID: 'HsbP',
|
|
2322
|
+
Inpt: descriptor_1.ClrS.encode(f.filter.inputMode),
|
|
2323
|
+
Otpt: descriptor_1.ClrS.encode(f.filter.rowOrder),
|
|
2324
|
+
}, filterID: 1215521360 });
|
|
2325
|
+
default: throw new Error(`Unknown filter type: ${f.type}`);
|
|
2286
2326
|
}
|
|
2287
2327
|
}
|
|
2288
2328
|
// let t: any;
|
|
@@ -2373,7 +2413,10 @@ addHandler('SoLd', hasKey('placedLayer'), (reader, target, left) => {
|
|
|
2373
2413
|
if (!placed.id || typeof placed.id !== 'string' || !/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/.test(placed.id)) {
|
|
2374
2414
|
throw new Error('Placed layer ID must be in a GUID format (example: 20953ddb-9391-11ec-b4f1-c15674f50bc4)');
|
|
2375
2415
|
}
|
|
2376
|
-
const
|
|
2416
|
+
const placedType = placedLayerTypes.indexOf(placed.type);
|
|
2417
|
+
if (placedType === -1)
|
|
2418
|
+
throw new Error('Invalid placedLayer type');
|
|
2419
|
+
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,
|
|
2377
2420
|
// quiltWarp: {} as any,
|
|
2378
2421
|
warp: encodeWarp(getWarpFromPlacedLayer(placed)), 'Sz ': {
|
|
2379
2422
|
_name: '',
|
|
@@ -2451,7 +2494,7 @@ addHandler('Lr32', () => false, (reader, _target, _left, psd, imageResources) =>
|
|
|
2451
2494
|
addHandler('LMsk', hasKey('userMask'), (reader, target) => {
|
|
2452
2495
|
target.userMask = {
|
|
2453
2496
|
colorSpace: (0, psdReader_1.readColor)(reader),
|
|
2454
|
-
opacity: (0, psdReader_1.readUint16)(reader) /
|
|
2497
|
+
opacity: (0, psdReader_1.readUint16)(reader) / 100,
|
|
2455
2498
|
};
|
|
2456
2499
|
const flag = (0, psdReader_1.readUint8)(reader);
|
|
2457
2500
|
if (flag !== 128)
|
|
@@ -2460,7 +2503,7 @@ addHandler('LMsk', hasKey('userMask'), (reader, target) => {
|
|
|
2460
2503
|
}, (writer, target) => {
|
|
2461
2504
|
const userMask = target.userMask;
|
|
2462
2505
|
(0, psdWriter_1.writeColor)(writer, userMask.colorSpace);
|
|
2463
|
-
(0, psdWriter_1.writeUint16)(writer, (0, helpers_1.clamp)(userMask.opacity, 0, 1) *
|
|
2506
|
+
(0, psdWriter_1.writeUint16)(writer, Math.round((0, helpers_1.clamp)(userMask.opacity, 0, 1) * 100));
|
|
2464
2507
|
(0, psdWriter_1.writeUint8)(writer, 128);
|
|
2465
2508
|
(0, psdWriter_1.writeZeros)(writer, 1);
|
|
2466
2509
|
});
|
|
@@ -2580,7 +2623,8 @@ addHandler('Anno', target => target.annotations !== undefined, (reader, target,
|
|
|
2580
2623
|
const count = (0, psdReader_1.readUint32)(reader);
|
|
2581
2624
|
const annotations = [];
|
|
2582
2625
|
for (let i = 0; i < count; i++) {
|
|
2583
|
-
|
|
2626
|
+
const recordStart = reader.offset;
|
|
2627
|
+
const length = (0, psdReader_1.readUint32)(reader); // includes the length field itself
|
|
2584
2628
|
const type = (0, psdReader_1.readSignature)(reader);
|
|
2585
2629
|
const open = !!(0, psdReader_1.readUint8)(reader);
|
|
2586
2630
|
/*const flags =*/ (0, psdReader_1.readUint8)(reader); // always 28
|
|
@@ -2596,11 +2640,12 @@ addHandler('Anno', target => target.annotations !== undefined, (reader, target,
|
|
|
2596
2640
|
const dataLength = (0, psdReader_1.readUint32)(reader);
|
|
2597
2641
|
let data;
|
|
2598
2642
|
if (type === 'txtA') {
|
|
2643
|
+
const dataStart = reader.offset;
|
|
2599
2644
|
if (dataLength >= 2 && (0, psdReader_1.readUint16)(reader) === 0xfeff) {
|
|
2600
|
-
data = (0, psdReader_1.readUnicodeStringWithLength)(reader, (dataLength - 2) / 2);
|
|
2645
|
+
data = (0, psdReader_1.readUnicodeStringWithLength)(reader, Math.floor((dataLength - 2) / 2));
|
|
2601
2646
|
}
|
|
2602
2647
|
else {
|
|
2603
|
-
reader.offset
|
|
2648
|
+
reader.offset = dataStart;
|
|
2604
2649
|
data = (0, psdReader_1.readAsciiString)(reader, dataLength);
|
|
2605
2650
|
}
|
|
2606
2651
|
data = data.replace(/\r/g, '\n');
|
|
@@ -2614,6 +2659,8 @@ addHandler('Anno', target => target.annotations !== undefined, (reader, target,
|
|
|
2614
2659
|
annotations.push({
|
|
2615
2660
|
type: type === 'txtA' ? 'text' : 'sound', open, iconLocation, popupLocation, color, author, name, date, data,
|
|
2616
2661
|
});
|
|
2662
|
+
if (length >= (reader.offset - recordStart))
|
|
2663
|
+
reader.offset = recordStart + length;
|
|
2617
2664
|
}
|
|
2618
2665
|
target.annotations = annotations;
|
|
2619
2666
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
@@ -2741,11 +2788,12 @@ function createLnkHandler(tag) {
|
|
|
2741
2788
|
}
|
|
2742
2789
|
(0, psdReader_1.skipBytes)(reader, left()); // ?
|
|
2743
2790
|
}, (writer, target) => {
|
|
2744
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
2791
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2745
2792
|
const psd = target;
|
|
2746
2793
|
for (const file of psd.linkedFiles) {
|
|
2747
2794
|
if ((tag === 'lnkE') !== !!file.linkedFile)
|
|
2748
2795
|
continue;
|
|
2796
|
+
const external = tag === 'lnkE';
|
|
2749
2797
|
let version = 2;
|
|
2750
2798
|
if (file.assetLockedState != null)
|
|
2751
2799
|
version = 7;
|
|
@@ -2753,11 +2801,13 @@ function createLnkHandler(tag) {
|
|
|
2753
2801
|
version = 6;
|
|
2754
2802
|
else if (file.childDocumentID != null)
|
|
2755
2803
|
version = 5;
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2804
|
+
// liFE version 2 is the only one with embedded data, it has no date and its file size is the size of the data,
|
|
2805
|
+
// versions 5+ can't store the data, so it's not written in that case
|
|
2806
|
+
else if (external && !file.data)
|
|
2807
|
+
version = 4;
|
|
2808
|
+
(0, psdWriter_1.writeUint64)(writer, 0);
|
|
2759
2809
|
const sizeOffset = writer.offset;
|
|
2760
|
-
(0, psdWriter_1.writeSignature)(writer,
|
|
2810
|
+
(0, psdWriter_1.writeSignature)(writer, external ? 'liFE' : (file.data ? 'liFD' : 'liFA'));
|
|
2761
2811
|
(0, psdWriter_1.writeInt32)(writer, version);
|
|
2762
2812
|
if (!file.id || typeof file.id !== 'string' || !/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/.test(file.id)) {
|
|
2763
2813
|
throw new Error('Linked file ID must be in a GUID format (example: 20953ddb-9391-11ec-b4f1-c15674f50bc4)');
|
|
@@ -2766,7 +2816,7 @@ function createLnkHandler(tag) {
|
|
|
2766
2816
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, file.name || '');
|
|
2767
2817
|
(0, psdWriter_1.writeSignature)(writer, file.type ? `${file.type} `.substring(0, 4) : ' ');
|
|
2768
2818
|
(0, psdWriter_1.writeSignature)(writer, file.creator ? `${file.creator} `.substring(0, 4) : '\0\0\0\0');
|
|
2769
|
-
|
|
2819
|
+
(0, psdWriter_1.writeUint64)(writer, (!external && file.data) ? file.data.byteLength : 0);
|
|
2770
2820
|
if (file.descriptor && file.descriptor.compInfo) {
|
|
2771
2821
|
const desc = {
|
|
2772
2822
|
compInfo: {
|
|
@@ -2780,7 +2830,7 @@ function createLnkHandler(tag) {
|
|
|
2780
2830
|
else {
|
|
2781
2831
|
(0, psdWriter_1.writeUint8)(writer, 0);
|
|
2782
2832
|
}
|
|
2783
|
-
if (
|
|
2833
|
+
if (external) {
|
|
2784
2834
|
const desc = {
|
|
2785
2835
|
descVersion: 2,
|
|
2786
2836
|
'Nm ': (_b = (_a = file.linkedFile) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '',
|
|
@@ -2789,6 +2839,8 @@ function createLnkHandler(tag) {
|
|
|
2789
2839
|
relPath: (_h = (_g = file.linkedFile) === null || _g === void 0 ? void 0 : _g.relativePath) !== null && _h !== void 0 ? _h : '',
|
|
2790
2840
|
};
|
|
2791
2841
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'ExternalFileLink', desc);
|
|
2842
|
+
}
|
|
2843
|
+
if (external && version > 3) {
|
|
2792
2844
|
const time = file.time ? new Date(file.time) : new Date();
|
|
2793
2845
|
(0, psdWriter_1.writeInt32)(writer, time.getUTCFullYear());
|
|
2794
2846
|
(0, psdWriter_1.writeUint8)(writer, time.getUTCMonth());
|
|
@@ -2797,11 +2849,14 @@ function createLnkHandler(tag) {
|
|
|
2797
2849
|
(0, psdWriter_1.writeUint8)(writer, time.getUTCMinutes());
|
|
2798
2850
|
(0, psdWriter_1.writeFloat64)(writer, time.getUTCSeconds() + time.getUTCMilliseconds() / 1000);
|
|
2799
2851
|
}
|
|
2800
|
-
if (
|
|
2801
|
-
(0, psdWriter_1.
|
|
2852
|
+
if (external) {
|
|
2853
|
+
(0, psdWriter_1.writeUint64)(writer, (version === 2 ? (_j = file.data) === null || _j === void 0 ? void 0 : _j.byteLength : (_k = file.linkedFile) === null || _k === void 0 ? void 0 : _k.fileSize) || 0); // file size
|
|
2854
|
+
}
|
|
2855
|
+
else if (file.data) {
|
|
2856
|
+
(0, psdWriter_1.writeBytes)(writer, file.data); // liFD
|
|
2802
2857
|
}
|
|
2803
2858
|
else {
|
|
2804
|
-
|
|
2859
|
+
(0, psdWriter_1.writeZeros)(writer, 8); // liFA
|
|
2805
2860
|
}
|
|
2806
2861
|
if (version >= 5)
|
|
2807
2862
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, file.childDocumentID || '');
|
|
@@ -2809,6 +2864,8 @@ function createLnkHandler(tag) {
|
|
|
2809
2864
|
(0, psdWriter_1.writeFloat64)(writer, file.assetModTime || 0);
|
|
2810
2865
|
if (version >= 7)
|
|
2811
2866
|
(0, psdWriter_1.writeUint8)(writer, file.assetLockedState || 0);
|
|
2867
|
+
if (external && version === 2 && file.data)
|
|
2868
|
+
(0, psdWriter_1.writeBytes)(writer, file.data);
|
|
2812
2869
|
let size = writer.offset - sizeOffset;
|
|
2813
2870
|
writer.view.setUint32(sizeOffset - 4, size, false); // write size
|
|
2814
2871
|
while (size % 4) {
|
|
@@ -3181,10 +3238,15 @@ addHandler('phfl', adjustmentType('photo filter'), (reader, target, left) => {
|
|
|
3181
3238
|
}
|
|
3182
3239
|
else { // version 3
|
|
3183
3240
|
// TODO: test this, this is probably wrong
|
|
3241
|
+
// values are stored as L (0..100), a, b (-128..127) multiplied by 100,
|
|
3242
|
+
// normalize them to the same scale as readColor() so they can be written back as version 2
|
|
3243
|
+
const l = (0, psdReader_1.readInt32)(reader) / 100;
|
|
3244
|
+
const a = (0, psdReader_1.readInt32)(reader) / 100;
|
|
3245
|
+
const b = (0, psdReader_1.readInt32)(reader) / 100;
|
|
3184
3246
|
color = {
|
|
3185
|
-
l:
|
|
3186
|
-
a: (0,
|
|
3187
|
-
b: (0,
|
|
3247
|
+
l: l / 100,
|
|
3248
|
+
a: (0, helpers_1.normalizeLabAB)(a),
|
|
3249
|
+
b: (0, helpers_1.normalizeLabAB)(b),
|
|
3188
3250
|
};
|
|
3189
3251
|
}
|
|
3190
3252
|
target.adjustment = {
|
|
@@ -3198,7 +3260,7 @@ addHandler('phfl', adjustmentType('photo filter'), (reader, target, left) => {
|
|
|
3198
3260
|
const info = target.adjustment;
|
|
3199
3261
|
(0, psdWriter_1.writeUint16)(writer, 2); // version
|
|
3200
3262
|
(0, psdWriter_1.writeColor)(writer, info.color || { l: 0, a: 0, b: 0 });
|
|
3201
|
-
(0, psdWriter_1.writeUint32)(writer, (info.density || 0) * 100);
|
|
3263
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round(Math.max(0, info.density || 0) * 100));
|
|
3202
3264
|
(0, psdWriter_1.writeUint8)(writer, info.preserveLuminosity ? 1 : 0);
|
|
3203
3265
|
(0, psdWriter_1.writeZeros)(writer, 3);
|
|
3204
3266
|
});
|
|
@@ -3401,10 +3463,11 @@ addHandler('grdm', adjustmentType('gradient map'), (reader, target, left) => {
|
|
|
3401
3463
|
(0, psdReader_1.readUint16)(reader) / 0x8000,
|
|
3402
3464
|
];
|
|
3403
3465
|
(0, psdReader_1.skipBytes)(reader, left());
|
|
3466
|
+
// stop locations are always in 0..4096 range, independent of smoothness
|
|
3404
3467
|
for (const s of info.colorStops)
|
|
3405
|
-
s.location /=
|
|
3468
|
+
s.location /= 4096;
|
|
3406
3469
|
for (const s of info.opacityStops)
|
|
3407
|
-
s.location /=
|
|
3470
|
+
s.location /= 4096;
|
|
3408
3471
|
target.adjustment = info;
|
|
3409
3472
|
}, (writer, target) => {
|
|
3410
3473
|
var _a, _b, _c;
|
|
@@ -3417,18 +3480,18 @@ addHandler('grdm', adjustmentType('gradient map'), (reader, target, left) => {
|
|
|
3417
3480
|
}
|
|
3418
3481
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, info.name || '');
|
|
3419
3482
|
(0, psdWriter_1.writeUint16)(writer, info.colorStops && info.colorStops.length || 0);
|
|
3420
|
-
const interpolation = Math.round(((_a = info.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096);
|
|
3483
|
+
const interpolation = Math.round((0, helpers_1.clamp)((_a = info.smoothness) !== null && _a !== void 0 ? _a : 1, 0, 1) * 4096);
|
|
3421
3484
|
for (const s of info.colorStops || []) {
|
|
3422
|
-
(0, psdWriter_1.writeUint32)(writer, Math.round(s.location *
|
|
3485
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round((0, helpers_1.clamp)(s.location, 0, 1) * 4096));
|
|
3423
3486
|
(0, psdWriter_1.writeUint32)(writer, Math.round(s.midpoint * 100));
|
|
3424
3487
|
(0, psdWriter_1.writeColor)(writer, s.color);
|
|
3425
3488
|
(0, psdWriter_1.writeZeros)(writer, 2);
|
|
3426
3489
|
}
|
|
3427
3490
|
(0, psdWriter_1.writeUint16)(writer, info.opacityStops && info.opacityStops.length || 0);
|
|
3428
3491
|
for (const s of info.opacityStops || []) {
|
|
3429
|
-
(0, psdWriter_1.writeUint32)(writer, Math.round(s.location *
|
|
3492
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round((0, helpers_1.clamp)(s.location, 0, 1) * 4096));
|
|
3430
3493
|
(0, psdWriter_1.writeUint32)(writer, Math.round(s.midpoint * 100));
|
|
3431
|
-
(0, psdWriter_1.writeUint16)(writer, Math.round(s.opacity * 0xff));
|
|
3494
|
+
(0, psdWriter_1.writeUint16)(writer, Math.round((0, helpers_1.clamp)(s.opacity, 0, 1) * 0xff));
|
|
3432
3495
|
}
|
|
3433
3496
|
(0, psdWriter_1.writeUint16)(writer, 2); // expansion count
|
|
3434
3497
|
(0, psdWriter_1.writeUint16)(writer, interpolation);
|
|
@@ -3590,7 +3653,7 @@ addHandler('Txt2', hasKey('engineData'), (reader, target, left, psd) => {
|
|
|
3590
3653
|
const data = (0, psdReader_1.readBytes)(reader, left());
|
|
3591
3654
|
target.engineData = (0, base64_js_1.fromByteArray)(data);
|
|
3592
3655
|
const layersByIndex = getTextLayersSortedByIndex(psd);
|
|
3593
|
-
const engineData = (0, engineData_1.parseEngineData)(data);
|
|
3656
|
+
const engineData = (0, engineData_1.parseEngineData)(data, reader);
|
|
3594
3657
|
const engineData2 = (0, engineData2_1.decodeEngineData2)(engineData);
|
|
3595
3658
|
const TextFrameSet = engineData2.ResourceDict.TextFrameSet;
|
|
3596
3659
|
if (TextFrameSet) {
|
|
@@ -3672,7 +3735,6 @@ addHandler('FEid', hasKey('filterEffectsMasks'), (reader, target, leftBytes) =>
|
|
|
3672
3735
|
}
|
|
3673
3736
|
}
|
|
3674
3737
|
}, (writer, target) => {
|
|
3675
|
-
var _a;
|
|
3676
3738
|
(0, psdWriter_1.writeInt32)(writer, 3); // version
|
|
3677
3739
|
for (const mask of target.filterEffectsMasks) {
|
|
3678
3740
|
(0, psdWriter_1.writeUint32)(writer, 0);
|
|
@@ -3701,7 +3763,7 @@ addHandler('FEid', hasKey('filterEffectsMasks'), (reader, target, leftBytes) =>
|
|
|
3701
3763
|
}
|
|
3702
3764
|
}
|
|
3703
3765
|
writer.view.setUint32(length2Offset - 4, writer.offset - length2Offset, false);
|
|
3704
|
-
const extra =
|
|
3766
|
+
const extra = mask.extra;
|
|
3705
3767
|
if (extra) {
|
|
3706
3768
|
(0, psdWriter_1.writeUint8)(writer, 1);
|
|
3707
3769
|
(0, psdWriter_1.writeInt32)(writer, extra.top);
|
|
@@ -3725,12 +3787,12 @@ addHandlerAlias('FXid', 'FEid');
|
|
|
3725
3787
|
addHandler('FMsk', hasKey('filterMask'), (reader, target) => {
|
|
3726
3788
|
target.filterMask = {
|
|
3727
3789
|
colorSpace: (0, psdReader_1.readColor)(reader),
|
|
3728
|
-
opacity: (0, psdReader_1.readUint16)(reader) /
|
|
3790
|
+
opacity: (0, psdReader_1.readUint16)(reader) / 100,
|
|
3729
3791
|
};
|
|
3730
3792
|
}, (writer, target) => {
|
|
3731
3793
|
var _a;
|
|
3732
3794
|
(0, psdWriter_1.writeColor)(writer, target.filterMask.colorSpace);
|
|
3733
|
-
(0, psdWriter_1.writeUint16)(writer, (0, helpers_1.clamp)((_a = target.filterMask.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) *
|
|
3795
|
+
(0, psdWriter_1.writeUint16)(writer, Math.round((0, helpers_1.clamp)((_a = target.filterMask.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 100));
|
|
3734
3796
|
});
|
|
3735
3797
|
addHandler('artd', // document-wide artboard info
|
|
3736
3798
|
// document-wide artboard info
|
|
@@ -3846,12 +3908,12 @@ addHandler('iOpa', hasKey('fillOpacity'), (reader, target) => {
|
|
|
3846
3908
|
target.fillOpacity = (0, psdReader_1.readUint8)(reader) / 0xff;
|
|
3847
3909
|
(0, psdReader_1.skipBytes)(reader, 3);
|
|
3848
3910
|
}, (writer, target) => {
|
|
3849
|
-
(0, psdWriter_1.writeUint8)(writer, target.fillOpacity * 0xff);
|
|
3911
|
+
(0, psdWriter_1.writeUint8)(writer, Math.round((0, helpers_1.clamp)(target.fillOpacity, 0, 1) * 0xff));
|
|
3850
3912
|
(0, psdWriter_1.writeZeros)(writer, 3);
|
|
3851
3913
|
});
|
|
3852
3914
|
addHandler('brst', hasKey('channelBlendingRestrictions'), (reader, target, left) => {
|
|
3853
3915
|
target.channelBlendingRestrictions = [];
|
|
3854
|
-
while (left()
|
|
3916
|
+
while (left() >= 4) {
|
|
3855
3917
|
target.channelBlendingRestrictions.push((0, psdReader_1.readInt32)(reader));
|
|
3856
3918
|
}
|
|
3857
3919
|
}, (writer, target) => {
|
|
@@ -3922,8 +3984,12 @@ exports.IntC = exports.IntE = exports.Drct = exports.WndM = exports.CntE = expor
|
|
|
3922
3984
|
exports.presetKindType = exports.prjM = exports.FlMd = void 0;
|
|
3923
3985
|
exports.setLogErrors = setLogErrors;
|
|
3924
3986
|
exports.readAsciiStringOrClassId = readAsciiStringOrClassId;
|
|
3987
|
+
exports.writeAsciiStringOrClassId = writeAsciiStringOrClassId;
|
|
3925
3988
|
exports.readDescriptorStructure = readDescriptorStructure;
|
|
3926
3989
|
exports.writeDescriptorStructure = writeDescriptorStructure;
|
|
3990
|
+
exports.createDescriptorReference = createDescriptorReference;
|
|
3991
|
+
exports.pathSelectionStateToReference = pathSelectionStateToReference;
|
|
3992
|
+
exports.writeClassStructure = writeClassStructure;
|
|
3927
3993
|
exports.readVersionAndDescriptor = readVersionAndDescriptor;
|
|
3928
3994
|
exports.writeVersionAndDescriptor = writeVersionAndDescriptor;
|
|
3929
3995
|
exports.horzVrtcToXY = horzVrtcToXY;
|
|
@@ -4062,6 +4128,8 @@ const fieldToExtType = {
|
|
|
4062
4128
|
origFXRefPoint: nullType,
|
|
4063
4129
|
FXRefPoint: nullType,
|
|
4064
4130
|
ClMg: makeType('', 'ClMg'),
|
|
4131
|
+
interpretation: makeType('', 'footageInterpretation'),
|
|
4132
|
+
bgColor: makeType('', 'NativeQuad'),
|
|
4065
4133
|
};
|
|
4066
4134
|
const fieldToArrayExtType = {
|
|
4067
4135
|
'Crv ': makeType('', 'CrPt'),
|
|
@@ -4095,6 +4163,9 @@ const fieldToArrayExtType = {
|
|
|
4095
4163
|
layerSettings: nullType,
|
|
4096
4164
|
list: nullType,
|
|
4097
4165
|
Adjs: makeType('', 'CrvA'),
|
|
4166
|
+
vertices: makeType('', 'Pnt '),
|
|
4167
|
+
warpedVertices: makeType('', 'Pnt '),
|
|
4168
|
+
quads: makeType('', 'quadIndices'),
|
|
4098
4169
|
};
|
|
4099
4170
|
const typeToField = {
|
|
4100
4171
|
'TEXT': [
|
|
@@ -4120,6 +4191,7 @@ const typeToField = {
|
|
|
4120
4191
|
'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
|
|
4121
4192
|
'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
|
|
4122
4193
|
'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
|
|
4194
|
+
'pixelSourceType',
|
|
4123
4195
|
],
|
|
4124
4196
|
'enum': [
|
|
4125
4197
|
'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
|
|
@@ -4130,6 +4202,7 @@ const typeToField = {
|
|
|
4130
4202
|
'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
|
|
4131
4203
|
'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
|
|
4132
4204
|
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
|
|
4205
|
+
'interpretAlpha',
|
|
4133
4206
|
],
|
|
4134
4207
|
'bool': [
|
|
4135
4208
|
'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
|
|
@@ -4142,14 +4215,15 @@ const typeToField = {
|
|
|
4142
4215
|
'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
|
|
4143
4216
|
'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
|
|
4144
4217
|
'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
|
|
4145
|
-
'moreAccurate', 'GpuY', 'LIWy', 'Cnty',
|
|
4218
|
+
'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn',
|
|
4146
4219
|
],
|
|
4147
4220
|
'doub': [
|
|
4148
4221
|
'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
|
|
4149
4222
|
'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
|
|
4150
4223
|
'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
|
|
4151
4224
|
'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
|
|
4152
|
-
'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3'
|
|
4225
|
+
'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3',
|
|
4226
|
+
'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity',
|
|
4153
4227
|
],
|
|
4154
4228
|
'UntF': [
|
|
4155
4229
|
'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
|
|
@@ -4165,14 +4239,57 @@ const typeToField = {
|
|
|
4165
4239
|
'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
|
|
4166
4240
|
'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList', 'ShrP',
|
|
4167
4241
|
'channelDenoise', 'Mtrx', 'layerSettings', 'list', 'compList', 'Adjs',
|
|
4242
|
+
'vertices', 'warpedVertices', 'quads', 'indices', 'Mpng',
|
|
4168
4243
|
],
|
|
4169
4244
|
'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
|
|
4170
4245
|
'obj ': ['null', 'Chnl'],
|
|
4171
4246
|
'Pth ': ['DspF'],
|
|
4247
|
+
'alis': ['alis'],
|
|
4172
4248
|
};
|
|
4173
4249
|
const channels = [
|
|
4174
4250
|
'Rd ', 'Grn ', 'Bl ', 'Yllw', 'Ylw ', 'Cyn ', 'Mgnt', 'Blck', 'Gry ', 'Lmnc', 'A ', 'B ',
|
|
4175
4251
|
];
|
|
4252
|
+
// color classes whose channel values are written as doubles ('GRYC' and 'LABC' are kept for backwards compatibility)
|
|
4253
|
+
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
|
+
// fallback for unknown keys, based on the type of the value
|
|
4274
|
+
function guessOSType(value) {
|
|
4275
|
+
if (typeof value === 'boolean')
|
|
4276
|
+
return 'bool';
|
|
4277
|
+
if (typeof value === 'number' && !Number.isInteger(value))
|
|
4278
|
+
return 'doub';
|
|
4279
|
+
if (Array.isArray(value))
|
|
4280
|
+
return 'VlLs';
|
|
4281
|
+
if (value && typeof value === 'object' && typeof value._classID === 'string')
|
|
4282
|
+
return 'Objc';
|
|
4283
|
+
return undefined;
|
|
4284
|
+
}
|
|
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
|
+
}
|
|
4176
4293
|
const fieldToArrayType = {
|
|
4177
4294
|
'Mnm ': 'long',
|
|
4178
4295
|
'Mxm ': 'long',
|
|
@@ -4212,6 +4329,8 @@ const fieldToArrayType = {
|
|
|
4212
4329
|
Mtrx: 'long',
|
|
4213
4330
|
compList: 'long',
|
|
4214
4331
|
Chnl: 'enum',
|
|
4332
|
+
indices: 'long',
|
|
4333
|
+
Mpng: 'long',
|
|
4215
4334
|
};
|
|
4216
4335
|
const fieldToType = {};
|
|
4217
4336
|
for (const type of Object.keys(typeToField)) {
|
|
@@ -4226,6 +4345,7 @@ for (const field of Object.keys(fieldToExtType)) {
|
|
|
4226
4345
|
for (const field of Object.keys(fieldToArrayExtType)) {
|
|
4227
4346
|
fieldToArrayType[field] = 'Objc';
|
|
4228
4347
|
}
|
|
4348
|
+
const pixelSourceOriginRoot = 'PixelSource.origin';
|
|
4229
4349
|
function getTypeByKey(key, value, root, parent) {
|
|
4230
4350
|
if (key === 'presetKind') {
|
|
4231
4351
|
return typeof value === 'string' ? 'enum' : 'long';
|
|
@@ -4245,7 +4365,7 @@ function getTypeByKey(key, value, root, parent) {
|
|
|
4245
4365
|
else if (key === 'AntA') {
|
|
4246
4366
|
return typeof value === 'string' ? 'enum' : 'bool';
|
|
4247
4367
|
}
|
|
4248
|
-
else if ((key === 'Hrzn' || key === 'Vrtc') && (parent.Type === 'keyType.Pstn' || parent._classID === 'Ofst')) {
|
|
4368
|
+
else if ((key === 'Hrzn' || key === 'Vrtc') && (parent.Type === 'keyType.Pstn' || parent._classID === 'Ofst' || root === pixelSourceOriginRoot)) {
|
|
4249
4369
|
return 'long';
|
|
4250
4370
|
}
|
|
4251
4371
|
else if (key === 'Hrzn' || key === 'Vrtc' || key === 'Top ' || key === 'Left' || key === 'Btom' || key === 'Rght') {
|
|
@@ -4262,6 +4382,15 @@ function getTypeByKey(key, value, root, parent) {
|
|
|
4262
4382
|
else if (key === 'Trnf') {
|
|
4263
4383
|
return Array.isArray(value) ? 'VlLs' : 'Objc';
|
|
4264
4384
|
}
|
|
4385
|
+
else if (key === 'alpha' && root === 'slices') {
|
|
4386
|
+
return 'long';
|
|
4387
|
+
}
|
|
4388
|
+
else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'HsbP') {
|
|
4389
|
+
return 'enum';
|
|
4390
|
+
}
|
|
4391
|
+
else if (key === 'LghD' && parent._classID === 'oilPaint') {
|
|
4392
|
+
return 'long';
|
|
4393
|
+
}
|
|
4265
4394
|
else {
|
|
4266
4395
|
return fieldToType[key];
|
|
4267
4396
|
}
|
|
@@ -4305,23 +4434,22 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
|
|
|
4305
4434
|
// write class structure
|
|
4306
4435
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
|
|
4307
4436
|
writeAsciiStringOrClassId(writer, classId);
|
|
4308
|
-
const
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
keyCount--;
|
|
4312
|
-
if ('_classID' in value)
|
|
4313
|
-
keyCount--;
|
|
4314
|
-
(0, psdWriter_1.writeUint32)(writer, keyCount);
|
|
4437
|
+
const allKeys = Object.keys(value);
|
|
4438
|
+
const keys = allKeys.filter(key => key !== '_name' && key !== '_classID' && value[key] !== undefined);
|
|
4439
|
+
(0, psdWriter_1.writeUint32)(writer, keys.length);
|
|
4315
4440
|
for (const key of keys) {
|
|
4316
|
-
if (key === '_name' || key === '_classID')
|
|
4317
|
-
continue;
|
|
4318
4441
|
let type = getTypeByKey(key, value[key], root, value);
|
|
4442
|
+
let childRoot = root;
|
|
4319
4443
|
let extType = fieldToExtType[key];
|
|
4320
4444
|
if (key === 'bounds' && root === 'text') {
|
|
4321
4445
|
extType = makeType('', 'bounds');
|
|
4322
4446
|
}
|
|
4323
4447
|
else if (key === 'origin') {
|
|
4324
4448
|
type = root === 'slices' ? 'enum' : 'Objc';
|
|
4449
|
+
if (classId === 'PixelSource') {
|
|
4450
|
+
extType = nullType; // stored as 'null' class with integer Hrzn/Vrtc
|
|
4451
|
+
childRoot = pixelSourceOriginRoot;
|
|
4452
|
+
}
|
|
4325
4453
|
}
|
|
4326
4454
|
else if ((key === 'Cyn ' || key === 'Mgnt' || key === 'Ylw ' || key === 'Blck') && value._classID === 'CMYC') {
|
|
4327
4455
|
type = 'doub';
|
|
@@ -4389,10 +4517,14 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
|
|
|
4389
4517
|
extType = nullType;
|
|
4390
4518
|
}
|
|
4391
4519
|
else if (channels.indexOf(key) !== -1) {
|
|
4392
|
-
type = (classId === 'RGBC' && root !== 'artd') ? 'doub' : 'long';
|
|
4520
|
+
type = ((classId === 'RGBC' && root !== 'artd') || doubleColorClasses.indexOf(classId) !== -1) ? 'doub' : 'long';
|
|
4393
4521
|
}
|
|
4394
4522
|
else if (key === 'profile') {
|
|
4395
|
-
type = classId === 'printOutput' ? 'TEXT' : 'tdta';
|
|
4523
|
+
type = (classId === 'printOutput' || classId === 'proofSetup') ? 'TEXT' : 'tdta';
|
|
4524
|
+
}
|
|
4525
|
+
else if (key === 'alis' && typeof value[key] === 'string') {
|
|
4526
|
+
// 'alis' is read as a binary string (one char per byte), strings with wider chars can only be stored as TEXT
|
|
4527
|
+
type = /[^\x00-\xff]/.test(value[key]) ? 'TEXT' : 'alis';
|
|
4396
4528
|
}
|
|
4397
4529
|
else if (key === 'strokeStyleContent') {
|
|
4398
4530
|
if (value[key]['Clr ']) {
|
|
@@ -4416,9 +4548,12 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
|
|
|
4416
4548
|
extType = { classID: 'HSBC', name: '' };
|
|
4417
4549
|
// TODO: other color spaces
|
|
4418
4550
|
}
|
|
4551
|
+
type = getRecordedOSType(value[key], type);
|
|
4552
|
+
if (!type)
|
|
4553
|
+
type = guessOSType(value[key]);
|
|
4419
4554
|
writeAsciiStringOrClassId(writer, key);
|
|
4420
4555
|
(0, psdWriter_1.writeSignature)(writer, type || 'long');
|
|
4421
|
-
writeOSType(writer, type || 'long', value[key], key, extType,
|
|
4556
|
+
writeOSType(writer, type || 'long', value[key], key, extType, childRoot);
|
|
4422
4557
|
if (logErrors && !type)
|
|
4423
4558
|
console.log(`Missing descriptor field type for: '${key}' in`, value);
|
|
4424
4559
|
}
|
|
@@ -4428,8 +4563,9 @@ function readOSType(reader, type, includeClass) {
|
|
|
4428
4563
|
case 'obj ': // Reference
|
|
4429
4564
|
return readReferenceStructure(reader);
|
|
4430
4565
|
case 'Objc': // Descriptor
|
|
4431
|
-
case 'GlbO': // GlobalObject same as Descriptor
|
|
4432
4566
|
return readDescriptorStructure(reader, includeClass);
|
|
4567
|
+
case 'GlbO': // GlobalObject same as Descriptor
|
|
4568
|
+
return setHidden(readDescriptorStructure(reader, includeClass), osTypeKey, type);
|
|
4433
4569
|
case 'VlLs': { // List
|
|
4434
4570
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4435
4571
|
const items = [];
|
|
@@ -4454,7 +4590,7 @@ function readOSType(reader, type, includeClass) {
|
|
|
4454
4590
|
const value = (0, psdReader_1.readFloat32)(reader);
|
|
4455
4591
|
if (!unitsMap[units])
|
|
4456
4592
|
throw new Error(`Invalid units: ${units}`);
|
|
4457
|
-
return { units: unitsMap[units], value };
|
|
4593
|
+
return setHidden({ units: unitsMap[units], value }, osTypeKey, type);
|
|
4458
4594
|
}
|
|
4459
4595
|
case 'TEXT': // String
|
|
4460
4596
|
return (0, psdReader_1.readUnicodeString)(reader);
|
|
@@ -4468,13 +4604,13 @@ function readOSType(reader, type, includeClass) {
|
|
|
4468
4604
|
case 'comp': { // Large Integer
|
|
4469
4605
|
const low = (0, psdReader_1.readUint32)(reader);
|
|
4470
4606
|
const high = (0, psdReader_1.readUint32)(reader);
|
|
4471
|
-
return { low, high };
|
|
4607
|
+
return setHidden({ low, high }, osTypeKey, type);
|
|
4472
4608
|
}
|
|
4473
4609
|
case 'bool': // Boolean
|
|
4474
4610
|
return !!(0, psdReader_1.readUint8)(reader);
|
|
4475
4611
|
case 'type': // Class
|
|
4476
4612
|
case 'GlbC': // Class
|
|
4477
|
-
return readClassStructure(reader);
|
|
4613
|
+
return setHidden(readClassStructure(reader), osTypeKey, type);
|
|
4478
4614
|
case 'alis': { // Alias
|
|
4479
4615
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4480
4616
|
return (0, psdReader_1.readAsciiString)(reader, length);
|
|
@@ -4486,21 +4622,21 @@ function readOSType(reader, type, includeClass) {
|
|
|
4486
4622
|
case 'ObAr': { // Object array
|
|
4487
4623
|
(0, psdReader_1.readInt32)(reader); // version: 16
|
|
4488
4624
|
(0, psdReader_1.readUnicodeString)(reader); // name: ''
|
|
4489
|
-
readAsciiStringOrClassId(reader); // 'rationalPoint'
|
|
4625
|
+
const classID = readAsciiStringOrClassId(reader); // 'rationalPoint'
|
|
4490
4626
|
const length = (0, psdReader_1.readInt32)(reader);
|
|
4491
4627
|
const items = [];
|
|
4492
4628
|
for (let i = 0; i < length; i++) {
|
|
4493
4629
|
const type1 = readAsciiStringOrClassId(reader); // type Hrzn | Vrtc
|
|
4494
|
-
(0, psdReader_1.readSignature)(reader); // UnFl
|
|
4495
|
-
(0, psdReader_1.readSignature)(reader); // units ? '#Pxl'
|
|
4630
|
+
const valueType = (0, psdReader_1.readSignature)(reader); // UnFl
|
|
4631
|
+
const units = (0, psdReader_1.readSignature)(reader); // units ? '#Pxl'
|
|
4496
4632
|
const valuesCount = (0, psdReader_1.readInt32)(reader);
|
|
4497
4633
|
const values = [];
|
|
4498
4634
|
for (let j = 0; j < valuesCount; j++) {
|
|
4499
4635
|
values.push((0, psdReader_1.readFloat64)(reader));
|
|
4500
4636
|
}
|
|
4501
|
-
items.push({ type: type1, values });
|
|
4637
|
+
items.push(setHidden({ type: type1, values }, obArInfoKey, { valueType, units }));
|
|
4502
4638
|
}
|
|
4503
|
-
return items;
|
|
4639
|
+
return setHidden(items, obArInfoKey, { classID });
|
|
4504
4640
|
}
|
|
4505
4641
|
case 'Pth ': { // File path
|
|
4506
4642
|
/*const length =*/ (0, psdReader_1.readInt32)(reader); // total size of all fields below
|
|
@@ -4520,6 +4656,7 @@ const ObArTypes = {
|
|
|
4520
4656
|
quiltSliceY: 'UntF',
|
|
4521
4657
|
};
|
|
4522
4658
|
function writeOSType(writer, type, value, key, extType, root) {
|
|
4659
|
+
var _a, _b, _c, _d, _e;
|
|
4523
4660
|
switch (type) {
|
|
4524
4661
|
case 'obj ': // Reference
|
|
4525
4662
|
writeReferenceStructure(writer, key, value);
|
|
@@ -4528,9 +4665,9 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4528
4665
|
case 'GlbO': { // GlobalObject same as Descriptor
|
|
4529
4666
|
if (typeof value !== 'object')
|
|
4530
4667
|
throw new Error(`Invalid struct value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4531
|
-
if (!extType)
|
|
4668
|
+
if (!extType && !value._classID)
|
|
4532
4669
|
throw new Error(`Missing ext type for: '${key}' (${JSON.stringify(value)})`);
|
|
4533
|
-
const name = value._name || extType.name;
|
|
4670
|
+
const name = value._name || (extType === null || extType === void 0 ? void 0 : extType.name) || '';
|
|
4534
4671
|
const classID = value._classID || extType.classID;
|
|
4535
4672
|
writeDescriptorStructure(writer, name, classID, value, root);
|
|
4536
4673
|
break;
|
|
@@ -4540,7 +4677,7 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4540
4677
|
throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4541
4678
|
(0, psdWriter_1.writeInt32)(writer, value.length);
|
|
4542
4679
|
for (let i = 0; i < value.length; i++) {
|
|
4543
|
-
const type = fieldToArrayType[key];
|
|
4680
|
+
const type = (_a = getRecordedOSType(value[i], fieldToArrayType[key])) !== null && _a !== void 0 ? _a : guessOSType(value[i]);
|
|
4544
4681
|
(0, psdWriter_1.writeSignature)(writer, type || 'long');
|
|
4545
4682
|
writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
|
|
4546
4683
|
if (logErrors && !type)
|
|
@@ -4578,20 +4715,35 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4578
4715
|
case 'long': // Integer
|
|
4579
4716
|
if (typeof value !== 'number')
|
|
4580
4717
|
throw new Error(`Invalid integer value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4581
|
-
(0, psdWriter_1.writeInt32)(writer, value);
|
|
4718
|
+
(0, psdWriter_1.writeInt32)(writer, Math.round(value)); // round instead of truncating fractional values
|
|
4719
|
+
break;
|
|
4720
|
+
case 'comp': // Large Integer
|
|
4721
|
+
if (!value || typeof value !== 'object')
|
|
4722
|
+
throw new Error(`Invalid large integer value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4723
|
+
(0, psdWriter_1.writeUint32)(writer, value.low >>> 0);
|
|
4724
|
+
(0, psdWriter_1.writeUint32)(writer, value.high >>> 0);
|
|
4582
4725
|
break;
|
|
4583
|
-
// case 'comp': // Large Integer
|
|
4584
|
-
// writeLargeInteger(reader);
|
|
4585
4726
|
case 'bool': // Boolean
|
|
4586
4727
|
if (typeof value !== 'boolean')
|
|
4587
4728
|
throw new Error(`Invalid boolean value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4588
4729
|
(0, psdWriter_1.writeUint8)(writer, value ? 1 : 0);
|
|
4589
4730
|
break;
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4731
|
+
case 'type': // Class
|
|
4732
|
+
case 'GlbC': // Class
|
|
4733
|
+
if (!value || typeof value !== 'object')
|
|
4734
|
+
throw new Error(`Invalid class value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4735
|
+
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, value.name || '');
|
|
4736
|
+
writeAsciiStringOrClassId(writer, value.classID);
|
|
4737
|
+
break;
|
|
4738
|
+
case 'alis': { // Alias (read as a binary string, one char per byte)
|
|
4739
|
+
if (typeof value !== 'string')
|
|
4740
|
+
throw new Error(`Invalid alias value: ${JSON.stringify(value)}, key: ${key}`);
|
|
4741
|
+
(0, psdWriter_1.writeInt32)(writer, value.length);
|
|
4742
|
+
for (let i = 0; i < value.length; i++) {
|
|
4743
|
+
(0, psdWriter_1.writeUint8)(writer, value.charCodeAt(i) & 0xff);
|
|
4744
|
+
}
|
|
4745
|
+
break;
|
|
4746
|
+
}
|
|
4595
4747
|
case 'tdta': // Raw Data
|
|
4596
4748
|
(0, psdWriter_1.writeInt32)(writer, value.byteLength);
|
|
4597
4749
|
(0, psdWriter_1.writeBytes)(writer, value);
|
|
@@ -4599,15 +4751,16 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4599
4751
|
case 'ObAr': { // Object array
|
|
4600
4752
|
(0, psdWriter_1.writeInt32)(writer, 16); // version
|
|
4601
4753
|
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, ''); // name
|
|
4602
|
-
const type = ObArTypes[key];
|
|
4754
|
+
const type = (_c = (_b = getHidden(value, obArInfoKey)) === null || _b === void 0 ? void 0 : _b.classID) !== null && _c !== void 0 ? _c : ObArTypes[key];
|
|
4603
4755
|
if (!type)
|
|
4604
4756
|
throw new Error(`Not implemented ObArType for: ${key}`);
|
|
4605
4757
|
writeAsciiStringOrClassId(writer, type);
|
|
4606
4758
|
(0, psdWriter_1.writeInt32)(writer, value.length);
|
|
4607
4759
|
for (let i = 0; i < value.length; i++) {
|
|
4760
|
+
const info = getHidden(value[i], obArInfoKey);
|
|
4608
4761
|
writeAsciiStringOrClassId(writer, value[i].type); // Hrzn | Vrtc
|
|
4609
|
-
(0, psdWriter_1.writeSignature)(writer, 'UnFl');
|
|
4610
|
-
(0, psdWriter_1.writeSignature)(writer, '#Pxl');
|
|
4762
|
+
(0, psdWriter_1.writeSignature)(writer, (_d = info === null || info === void 0 ? void 0 : info.valueType) !== null && _d !== void 0 ? _d : 'UnFl');
|
|
4763
|
+
(0, psdWriter_1.writeSignature)(writer, (_e = info === null || info === void 0 ? void 0 : info.units) !== null && _e !== void 0 ? _e : '#Pxl');
|
|
4611
4764
|
(0, psdWriter_1.writeInt32)(writer, value[i].values.length);
|
|
4612
4765
|
for (let j = 0; j < value[i].values.length; j++) {
|
|
4613
4766
|
(0, psdWriter_1.writeFloat64)(writer, value[i].values[j]);
|
|
@@ -4628,85 +4781,144 @@ function writeOSType(writer, type, value, key, extType, root) {
|
|
|
4628
4781
|
throw new Error(`Not implemented descriptor OSType: ${type}`);
|
|
4629
4782
|
}
|
|
4630
4783
|
}
|
|
4784
|
+
function referenceItemToValue(item) {
|
|
4785
|
+
switch (item.type) {
|
|
4786
|
+
case 'prop': return item.keyID;
|
|
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);
|
|
4805
|
+
}
|
|
4631
4806
|
function readReferenceStructure(reader) {
|
|
4632
4807
|
const itemsCount = (0, psdReader_1.readInt32)(reader);
|
|
4633
|
-
const
|
|
4808
|
+
const infos = [];
|
|
4634
4809
|
for (let i = 0; i < itemsCount; i++) {
|
|
4635
4810
|
const type = (0, psdReader_1.readSignature)(reader);
|
|
4636
4811
|
switch (type) {
|
|
4637
4812
|
case 'prop': { // Property
|
|
4638
|
-
readClassStructure(reader);
|
|
4813
|
+
const { name, classID } = readClassStructure(reader);
|
|
4639
4814
|
const keyID = readAsciiStringOrClassId(reader);
|
|
4640
|
-
|
|
4815
|
+
infos.push({ type, name, classID, keyID });
|
|
4641
4816
|
break;
|
|
4642
4817
|
}
|
|
4643
|
-
case 'Clss': // Class
|
|
4644
|
-
|
|
4818
|
+
case 'Clss': { // Class
|
|
4819
|
+
const { name, classID } = readClassStructure(reader);
|
|
4820
|
+
infos.push({ type, name, classID });
|
|
4645
4821
|
break;
|
|
4822
|
+
}
|
|
4646
4823
|
case 'Enmr': { // Enumerated Reference
|
|
4647
|
-
readClassStructure(reader);
|
|
4824
|
+
const { name, classID } = readClassStructure(reader);
|
|
4648
4825
|
const typeID = readAsciiStringOrClassId(reader);
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4826
|
+
const enumValue = readAsciiStringOrClassId(reader);
|
|
4827
|
+
infos.push({ type, name, classID, typeID, enumValue });
|
|
4651
4828
|
break;
|
|
4652
4829
|
}
|
|
4653
4830
|
case 'rele': { // Offset
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
items.push((0, psdReader_1.readUint32)(reader));
|
|
4831
|
+
const { name, classID } = readClassStructure(reader);
|
|
4832
|
+
infos.push({ type, name, classID, value: (0, psdReader_1.readUint32)(reader) });
|
|
4657
4833
|
break;
|
|
4658
4834
|
}
|
|
4659
4835
|
case 'Idnt': // Identifier
|
|
4660
|
-
items.push((0, psdReader_1.readInt32)(reader));
|
|
4661
|
-
break;
|
|
4662
4836
|
case 'indx': // Index
|
|
4663
|
-
|
|
4837
|
+
infos.push({ type, value: (0, psdReader_1.readInt32)(reader) });
|
|
4664
4838
|
break;
|
|
4665
4839
|
case 'name': { // Name
|
|
4666
|
-
readClassStructure(reader);
|
|
4667
|
-
|
|
4840
|
+
const { name, classID } = readClassStructure(reader);
|
|
4841
|
+
infos.push({ type, name, classID, value: (0, psdReader_1.readUnicodeString)(reader) });
|
|
4668
4842
|
break;
|
|
4669
4843
|
}
|
|
4670
4844
|
default:
|
|
4671
4845
|
throw new Error(`Invalid descriptor reference type: ${type}`);
|
|
4672
4846
|
}
|
|
4673
4847
|
}
|
|
4674
|
-
return
|
|
4848
|
+
return createDescriptorReference(infos);
|
|
4849
|
+
}
|
|
4850
|
+
function guessReferenceItem(value) {
|
|
4851
|
+
if (typeof value === 'string') {
|
|
4852
|
+
// enumerated references are read as `${typeID}.${enumValue}` where typeID is a 4 character ID or a string ID
|
|
4853
|
+
// (values like 'My.Path' or 'Logo.v2' can't be typeID/enum value, so they are written as name references)
|
|
4854
|
+
const match = /^([a-z ]{4}|[a-z]{5,})\.([a-z ]+)$/i.exec(value);
|
|
4855
|
+
if (match) {
|
|
4856
|
+
return { type: 'Enmr', name: '', classID: match[1], typeID: match[1], enumValue: match[2] };
|
|
4857
|
+
}
|
|
4858
|
+
else {
|
|
4859
|
+
return { type: 'name', name: '', classID: 'Lyr ', value };
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
else if (typeof value === 'number') {
|
|
4863
|
+
return { type: 'Idnt', value };
|
|
4864
|
+
}
|
|
4865
|
+
else if (value && typeof value === 'object' && typeof value.classID === 'string') {
|
|
4866
|
+
return { type: 'Clss', name: value.name || '', classID: value.classID };
|
|
4867
|
+
}
|
|
4868
|
+
else {
|
|
4869
|
+
throw new Error(`Invalid descriptor reference value: ${JSON.stringify(value)}`);
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
// path selection state (image resource 1088) is a reference to paths, enumerated references there use 'Path' class
|
|
4873
|
+
// (name references use 'Lyr ' class, they reference layer of the vector mask)
|
|
4874
|
+
function pathSelectionStateToReference(items) {
|
|
4875
|
+
const infos = getHidden(items, referenceInfoKey);
|
|
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
|
|
4879
|
+
const item = guessReferenceItem(value);
|
|
4880
|
+
if (item.type === 'Enmr')
|
|
4881
|
+
item.classID = 'Path';
|
|
4882
|
+
return item;
|
|
4883
|
+
}));
|
|
4675
4884
|
}
|
|
4676
4885
|
function writeReferenceStructure(writer, _key, items) {
|
|
4886
|
+
if (!Array.isArray(items))
|
|
4887
|
+
throw new Error(`Invalid reference value: ${JSON.stringify(items)}, key: ${_key}`);
|
|
4888
|
+
const infos = getHidden(items, referenceInfoKey);
|
|
4677
4889
|
(0, psdWriter_1.writeInt32)(writer, items.length);
|
|
4678
4890
|
for (let i = 0; i < items.length; i++) {
|
|
4679
4891
|
const value = items[i];
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
}
|
|
4688
|
-
}
|
|
4689
|
-
(0, psdWriter_1.writeSignature)(writer, type);
|
|
4690
|
-
switch (type) {
|
|
4691
|
-
// case 'prop': // Property
|
|
4692
|
-
// case 'Clss': // Class
|
|
4693
|
-
case 'Enmr': { // Enumerated Reference
|
|
4694
|
-
const [typeID, enumValue] = value.split('.');
|
|
4695
|
-
writeClassStructure(writer, '\0', typeID);
|
|
4696
|
-
writeAsciiStringOrClassId(writer, typeID);
|
|
4697
|
-
writeAsciiStringOrClassId(writer, enumValue);
|
|
4892
|
+
const recorded = infos === null || infos === void 0 ? void 0 : infos[i];
|
|
4893
|
+
const item = referenceItemMatches(recorded, value) ? recorded : guessReferenceItem(value);
|
|
4894
|
+
(0, psdWriter_1.writeSignature)(writer, item.type);
|
|
4895
|
+
switch (item.type) {
|
|
4896
|
+
case 'prop': // Property
|
|
4897
|
+
writeClassStructure(writer, item.name || '', item.classID);
|
|
4898
|
+
writeAsciiStringOrClassId(writer, item.keyID);
|
|
4698
4899
|
break;
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
(
|
|
4900
|
+
case 'Clss': // Class
|
|
4901
|
+
writeClassStructure(writer, item.name || '', item.classID);
|
|
4902
|
+
break;
|
|
4903
|
+
case 'Enmr': // Enumerated Reference
|
|
4904
|
+
writeClassStructure(writer, item.name || '', item.classID);
|
|
4905
|
+
writeAsciiStringOrClassId(writer, item.typeID);
|
|
4906
|
+
writeAsciiStringOrClassId(writer, item.enumValue);
|
|
4907
|
+
break;
|
|
4908
|
+
case 'rele': // Offset
|
|
4909
|
+
writeClassStructure(writer, item.name || '', item.classID);
|
|
4910
|
+
(0, psdWriter_1.writeUint32)(writer, item.value);
|
|
4911
|
+
break;
|
|
4912
|
+
case 'Idnt': // Identifier
|
|
4913
|
+
case 'indx': // Index
|
|
4914
|
+
(0, psdWriter_1.writeInt32)(writer, item.value);
|
|
4915
|
+
break;
|
|
4916
|
+
case 'name': // Name
|
|
4917
|
+
writeClassStructure(writer, item.name || '', item.classID);
|
|
4918
|
+
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, `${item.value}`);
|
|
4706
4919
|
break;
|
|
4707
|
-
}
|
|
4708
4920
|
default:
|
|
4709
|
-
throw new Error(`Invalid descriptor reference type: ${type}`);
|
|
4921
|
+
throw new Error(`Invalid descriptor reference type: ${item.type}`);
|
|
4710
4922
|
}
|
|
4711
4923
|
}
|
|
4712
4924
|
return items;
|
|
@@ -4717,7 +4929,7 @@ function readClassStructure(reader) {
|
|
|
4717
4929
|
return { name, classID };
|
|
4718
4930
|
}
|
|
4719
4931
|
function writeClassStructure(writer, name, classID) {
|
|
4720
|
-
(0, psdWriter_1.
|
|
4932
|
+
(0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
|
|
4721
4933
|
writeAsciiStringOrClassId(writer, classID);
|
|
4722
4934
|
}
|
|
4723
4935
|
function readVersionAndDescriptor(reader, includeClass = false) {
|
|
@@ -4849,9 +5061,11 @@ function serializeEffects(e, log, multi) {
|
|
|
4849
5061
|
info.numModifyingFX = 0;
|
|
4850
5062
|
for (const key of Object.keys(e)) {
|
|
4851
5063
|
const value = e[key];
|
|
5064
|
+
if (value == null || typeof value !== 'object')
|
|
5065
|
+
continue;
|
|
4852
5066
|
if (Array.isArray(value)) {
|
|
4853
5067
|
for (const effect of value) {
|
|
4854
|
-
if (effect.enabled)
|
|
5068
|
+
if (effect === null || effect === void 0 ? void 0 : effect.enabled)
|
|
4855
5069
|
info.numModifyingFX++;
|
|
4856
5070
|
}
|
|
4857
5071
|
}
|
|
@@ -5000,7 +5214,7 @@ function serializeTrackList(tracks) {
|
|
|
5000
5214
|
const t = tracks[i];
|
|
5001
5215
|
trackList.push(Object.assign(Object.assign({ trackID: exports.stdTrackID.encode(t.type), Vrsn: 1, enab: !!t.enabled, Effc: !!t.effectParams }, (t.effectParams ? {
|
|
5002
5216
|
effectParams: {
|
|
5003
|
-
keyList: serializeKeyList(t.keys),
|
|
5217
|
+
keyList: serializeKeyList(t.effectParams.keys),
|
|
5004
5218
|
fillCanvas: t.effectParams.fillCanvas,
|
|
5005
5219
|
zoomOrigin: t.effectParams.zoomOrigin,
|
|
5006
5220
|
}
|
|
@@ -5243,7 +5457,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
|
|
|
5243
5457
|
result.sdwO = unitsPercent(val);
|
|
5244
5458
|
break;
|
|
5245
5459
|
case 'angle':
|
|
5246
|
-
if (objName === 'gradientOverlay' || objName === '
|
|
5460
|
+
if (objName === 'gradientOverlay' || objName === 'patternOverlay') {
|
|
5247
5461
|
result.Angl = unitsAngle(val);
|
|
5248
5462
|
}
|
|
5249
5463
|
else {
|
|
@@ -5315,7 +5529,8 @@ function serializeEffectObject(obj, objName, reportErrors) {
|
|
|
5315
5529
|
}
|
|
5316
5530
|
function parseGradient(grad) {
|
|
5317
5531
|
if (grad.GrdF === 'GrdF.CstS') {
|
|
5318
|
-
|
|
5532
|
+
// stop locations are always in 0..4096 range, independent of smoothness (Intr)
|
|
5533
|
+
const samples = 4096;
|
|
5319
5534
|
return {
|
|
5320
5535
|
type: 'solid',
|
|
5321
5536
|
name: grad['Nm '],
|
|
@@ -5349,11 +5564,12 @@ function parseGradient(grad) {
|
|
|
5349
5564
|
function serializeGradient(grad) {
|
|
5350
5565
|
var _a, _b;
|
|
5351
5566
|
if (grad.type === 'solid') {
|
|
5352
|
-
|
|
5567
|
+
// stop locations are always in 0..4096 range, independent of smoothness (Intr)
|
|
5568
|
+
const samples = 4096;
|
|
5353
5569
|
return {
|
|
5354
5570
|
'Nm ': grad.name || '',
|
|
5355
5571
|
GrdF: 'GrdF.CstS',
|
|
5356
|
-
Intr:
|
|
5572
|
+
Intr: Math.round(((_a = grad.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096),
|
|
5357
5573
|
Clrs: grad.colorStops.map(s => {
|
|
5358
5574
|
var _a;
|
|
5359
5575
|
return ({
|
|
@@ -5382,8 +5598,8 @@ function serializeGradient(grad) {
|
|
|
5382
5598
|
ClrS: exports.ClrS.encode(grad.colorModel),
|
|
5383
5599
|
RndS: grad.randomSeed || 0,
|
|
5384
5600
|
Smth: Math.round(((_b = grad.roughness) !== null && _b !== void 0 ? _b : 1) * 4096),
|
|
5385
|
-
'Mnm ': (grad.min || [0, 0, 0, 0]).map(x => x * 100),
|
|
5386
|
-
'Mxm ': (grad.max || [1, 1, 1, 1]).map(x => x * 100),
|
|
5601
|
+
'Mnm ': (grad.min || [0, 0, 0, 0]).map(x => Math.round(x * 100)),
|
|
5602
|
+
'Mxm ': (grad.max || [1, 1, 1, 1]).map(x => Math.round(x * 100)),
|
|
5387
5603
|
};
|
|
5388
5604
|
}
|
|
5389
5605
|
}
|
|
@@ -5483,21 +5699,65 @@ function serializeVectorContent(content) {
|
|
|
5483
5699
|
return { key: 'GdFl', descriptor: serializeGradientContent(content) };
|
|
5484
5700
|
}
|
|
5485
5701
|
}
|
|
5702
|
+
// Descriptor color values: HSB saturation/brightness 0..100, CMYK 0..100, Gray 0..100, Lab L 0..100, a/b -128..127
|
|
5703
|
+
// 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
|
+
const colorConversions = {
|
|
5706
|
+
// key: [descriptor -> color, color -> descriptor]
|
|
5707
|
+
Strt: [x => x / 100, x => x * 100],
|
|
5708
|
+
Brgh: [x => x / 100, x => x * 100],
|
|
5709
|
+
'Cyn ': [x => x * 255 / 100, x => x * 100 / 255],
|
|
5710
|
+
Mgnt: [x => x * 255 / 100, x => x * 100 / 255],
|
|
5711
|
+
'Ylw ': [x => x * 255 / 100, x => x * 100 / 255],
|
|
5712
|
+
Blck: [x => x * 255 / 100, x => x * 100 / 255],
|
|
5713
|
+
'Gry ': [x => x * 255 / 100, x => x * 100 / 255],
|
|
5714
|
+
Lmnc: [x => x / 100, x => x * 100],
|
|
5715
|
+
'A ': [helpers_1.normalizeLabAB, helpers_1.denormalizeLabAB],
|
|
5716
|
+
'B ': [helpers_1.normalizeLabAB, helpers_1.denormalizeLabAB],
|
|
5717
|
+
};
|
|
5718
|
+
function colorToDescriptorValue(key, value) {
|
|
5719
|
+
const conversion = colorConversions[key];
|
|
5720
|
+
if (!conversion)
|
|
5721
|
+
return value;
|
|
5722
|
+
const [from, to] = conversion;
|
|
5723
|
+
const result = to(value);
|
|
5724
|
+
if (!isFinite(result))
|
|
5725
|
+
return result;
|
|
5726
|
+
// prefer shortest number that converts back to the same value (avoids values like 30.200000000000003)
|
|
5727
|
+
for (let precision = 1; precision < 17; precision++) {
|
|
5728
|
+
const candidate = +result.toPrecision(precision);
|
|
5729
|
+
if (from(candidate) === value)
|
|
5730
|
+
return candidate;
|
|
5731
|
+
}
|
|
5732
|
+
return result;
|
|
5733
|
+
}
|
|
5734
|
+
function shallowEqual(a, b) {
|
|
5735
|
+
const keys = Object.keys(a);
|
|
5736
|
+
if (keys.length !== Object.keys(b).length)
|
|
5737
|
+
return false;
|
|
5738
|
+
return keys.every(key => a[key] === b[key]);
|
|
5739
|
+
}
|
|
5486
5740
|
function parseColor(color) {
|
|
5741
|
+
let result;
|
|
5487
5742
|
if ('H ' in color) {
|
|
5488
|
-
|
|
5743
|
+
result = { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
|
|
5489
5744
|
}
|
|
5490
5745
|
else if ('Rd ' in color) {
|
|
5491
5746
|
return { r: color['Rd '], g: color['Grn '], b: color['Bl '] };
|
|
5492
5747
|
}
|
|
5493
5748
|
else if ('Cyn ' in color) {
|
|
5494
|
-
|
|
5749
|
+
result = {
|
|
5750
|
+
c: color['Cyn '] * 255 / 100,
|
|
5751
|
+
m: color.Mgnt * 255 / 100,
|
|
5752
|
+
y: color['Ylw '] * 255 / 100,
|
|
5753
|
+
k: color.Blck * 255 / 100,
|
|
5754
|
+
};
|
|
5495
5755
|
}
|
|
5496
5756
|
else if ('Gry ' in color) {
|
|
5497
|
-
|
|
5757
|
+
result = { k: color['Gry '] * 255 / 100 };
|
|
5498
5758
|
}
|
|
5499
5759
|
else if ('Lmnc' in color) {
|
|
5500
|
-
|
|
5760
|
+
result = { l: color.Lmnc / 100, a: (0, helpers_1.normalizeLabAB)(color['A ']), b: (0, helpers_1.normalizeLabAB)(color['B ']) };
|
|
5501
5761
|
}
|
|
5502
5762
|
else if ('redFloat' in color) {
|
|
5503
5763
|
return { fr: color.redFloat, fg: color.greenFloat, fb: color.blueFloat };
|
|
@@ -5505,8 +5765,10 @@ function parseColor(color) {
|
|
|
5505
5765
|
else {
|
|
5506
5766
|
throw new Error('Unsupported color descriptor');
|
|
5507
5767
|
}
|
|
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 });
|
|
5508
5770
|
}
|
|
5509
|
-
function
|
|
5771
|
+
function serializeColorValues(color) {
|
|
5510
5772
|
if (!color) {
|
|
5511
5773
|
return { _name: '', _classID: 'RGBC', 'Rd ': 0, 'Grn ': 0, 'Bl ': 0 };
|
|
5512
5774
|
}
|
|
@@ -5517,21 +5779,50 @@ function serializeColor(color) {
|
|
|
5517
5779
|
return { _name: '', _classID: 'RGBC', redFloat: color.fr, greenFloat: color.fg, blueFloat: color.fb };
|
|
5518
5780
|
}
|
|
5519
5781
|
else if ('h' in color) {
|
|
5520
|
-
return {
|
|
5782
|
+
return {
|
|
5783
|
+
_name: '', _classID: 'HSBC',
|
|
5784
|
+
'H ': unitsAngle((color.h || 0) * 360),
|
|
5785
|
+
Strt: colorToDescriptorValue('Strt', color.s || 0),
|
|
5786
|
+
Brgh: colorToDescriptorValue('Brgh', color.b || 0),
|
|
5787
|
+
};
|
|
5521
5788
|
}
|
|
5522
5789
|
else if ('c' in color) {
|
|
5523
|
-
return {
|
|
5790
|
+
return {
|
|
5791
|
+
_name: '', _classID: 'CMYC',
|
|
5792
|
+
'Cyn ': colorToDescriptorValue('Cyn ', color.c || 0),
|
|
5793
|
+
Mgnt: colorToDescriptorValue('Mgnt', color.m || 0),
|
|
5794
|
+
'Ylw ': colorToDescriptorValue('Ylw ', color.y || 0),
|
|
5795
|
+
Blck: colorToDescriptorValue('Blck', color.k || 0),
|
|
5796
|
+
};
|
|
5524
5797
|
}
|
|
5525
5798
|
else if ('l' in color) {
|
|
5526
|
-
return {
|
|
5799
|
+
return {
|
|
5800
|
+
_name: '', _classID: 'LbCl',
|
|
5801
|
+
Lmnc: colorToDescriptorValue('Lmnc', color.l || 0),
|
|
5802
|
+
'A ': colorToDescriptorValue('A ', color.a || 0),
|
|
5803
|
+
'B ': colorToDescriptorValue('B ', color.b || 0),
|
|
5804
|
+
};
|
|
5527
5805
|
}
|
|
5528
5806
|
else if ('k' in color) {
|
|
5529
|
-
return { _name: '', _classID: '
|
|
5807
|
+
return { _name: '', _classID: 'Grsc', 'Gry ': colorToDescriptorValue('Gry ', color.k || 0) };
|
|
5530
5808
|
}
|
|
5531
5809
|
else {
|
|
5532
5810
|
throw new Error('Invalid color value');
|
|
5533
5811
|
}
|
|
5534
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
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
return result;
|
|
5825
|
+
}
|
|
5535
5826
|
function parseAngle(x) {
|
|
5536
5827
|
if (x === undefined)
|
|
5537
5828
|
return 0;
|
|
@@ -5948,9 +6239,9 @@ function readEffects(reader) {
|
|
|
5948
6239
|
case 'cmnS': { // common state (see See Effects layer, common state info)
|
|
5949
6240
|
const size = (0, psdReader_1.readUint32)(reader);
|
|
5950
6241
|
const version = (0, psdReader_1.readUint32)(reader);
|
|
5951
|
-
|
|
6242
|
+
(0, psdReader_1.readUint8)(reader); // visible (not reliable, Photoshop writes 1 even if effects are disabled)
|
|
5952
6243
|
(0, psdReader_1.skipBytes)(reader, 2);
|
|
5953
|
-
if (size !== 7 || version !== 0
|
|
6244
|
+
if (size !== 7 || version !== 0)
|
|
5954
6245
|
throw new Error(`Invalid effects common state`);
|
|
5955
6246
|
break;
|
|
5956
6247
|
}
|
|
@@ -6098,7 +6389,7 @@ function writeShadowInfo(writer, shadow) {
|
|
|
6098
6389
|
(0, psdWriter_1.writeColor)(writer, shadow.color); // native color
|
|
6099
6390
|
}
|
|
6100
6391
|
function writeEffects(writer, effects) {
|
|
6101
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6392
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
6102
6393
|
const dropShadow = (_a = effects.dropShadow) === null || _a === void 0 ? void 0 : _a[0];
|
|
6103
6394
|
const innerShadow = (_b = effects.innerShadow) === null || _b === void 0 ? void 0 : _b[0];
|
|
6104
6395
|
const outerGlow = effects.outerGlow;
|
|
@@ -6124,7 +6415,7 @@ function writeEffects(writer, effects) {
|
|
|
6124
6415
|
(0, psdWriter_1.writeSignature)(writer, 'cmnS');
|
|
6125
6416
|
(0, psdWriter_1.writeUint32)(writer, 7); // size
|
|
6126
6417
|
(0, psdWriter_1.writeUint32)(writer, 0); // version
|
|
6127
|
-
(0, psdWriter_1.writeUint8)(writer, 1); // visible
|
|
6418
|
+
(0, psdWriter_1.writeUint8)(writer, 1); // visible (Photoshop writes 1 here even if effects are disabled)
|
|
6128
6419
|
(0, psdWriter_1.writeZeros)(writer, 2);
|
|
6129
6420
|
if (dropShadow) {
|
|
6130
6421
|
(0, psdWriter_1.writeSignature)(writer, '8BIM');
|
|
@@ -6146,7 +6437,7 @@ function writeEffects(writer, effects) {
|
|
|
6146
6437
|
(0, psdWriter_1.writeColor)(writer, outerGlow.color);
|
|
6147
6438
|
writeBlendMode(writer, outerGlow.blendMode);
|
|
6148
6439
|
(0, psdWriter_1.writeUint8)(writer, outerGlow.enabled ? 1 : 0);
|
|
6149
|
-
writeFixedPoint8(writer, outerGlow.opacity
|
|
6440
|
+
writeFixedPoint8(writer, (_e = outerGlow.opacity) !== null && _e !== void 0 ? _e : 1);
|
|
6150
6441
|
(0, psdWriter_1.writeColor)(writer, outerGlow.color);
|
|
6151
6442
|
}
|
|
6152
6443
|
if (innerGlow) {
|
|
@@ -6154,12 +6445,12 @@ function writeEffects(writer, effects) {
|
|
|
6154
6445
|
(0, psdWriter_1.writeSignature)(writer, 'iglw');
|
|
6155
6446
|
(0, psdWriter_1.writeUint32)(writer, 43);
|
|
6156
6447
|
(0, psdWriter_1.writeUint32)(writer, 2);
|
|
6157
|
-
(0, psdWriter_1.writeFixedPoint32)(writer, ((
|
|
6448
|
+
(0, psdWriter_1.writeFixedPoint32)(writer, ((_f = innerGlow.size) === null || _f === void 0 ? void 0 : _f.value) || 0);
|
|
6158
6449
|
(0, psdWriter_1.writeFixedPoint32)(writer, 0); // intensity
|
|
6159
6450
|
(0, psdWriter_1.writeColor)(writer, innerGlow.color);
|
|
6160
6451
|
writeBlendMode(writer, innerGlow.blendMode);
|
|
6161
6452
|
(0, psdWriter_1.writeUint8)(writer, innerGlow.enabled ? 1 : 0);
|
|
6162
|
-
writeFixedPoint8(writer, innerGlow.opacity
|
|
6453
|
+
writeFixedPoint8(writer, (_g = innerGlow.opacity) !== null && _g !== void 0 ? _g : 1);
|
|
6163
6454
|
(0, psdWriter_1.writeUint8)(writer, 0); // inverted
|
|
6164
6455
|
(0, psdWriter_1.writeColor)(writer, innerGlow.color);
|
|
6165
6456
|
}
|
|
@@ -6170,15 +6461,15 @@ function writeEffects(writer, effects) {
|
|
|
6170
6461
|
(0, psdWriter_1.writeUint32)(writer, 2);
|
|
6171
6462
|
(0, psdWriter_1.writeFixedPoint32)(writer, bevel.angle || 0);
|
|
6172
6463
|
(0, psdWriter_1.writeFixedPoint32)(writer, bevel.strength || 0);
|
|
6173
|
-
(0, psdWriter_1.writeFixedPoint32)(writer, ((
|
|
6464
|
+
(0, psdWriter_1.writeFixedPoint32)(writer, ((_h = bevel.size) === null || _h === void 0 ? void 0 : _h.value) || 0);
|
|
6174
6465
|
writeBlendMode(writer, bevel.highlightBlendMode);
|
|
6175
6466
|
writeBlendMode(writer, bevel.shadowBlendMode);
|
|
6176
6467
|
(0, psdWriter_1.writeColor)(writer, bevel.highlightColor);
|
|
6177
6468
|
(0, psdWriter_1.writeColor)(writer, bevel.shadowColor);
|
|
6178
6469
|
const style = bevelStyles.indexOf(bevel.style);
|
|
6179
|
-
(0, psdWriter_1.writeUint8)(writer, style <= 0 ?
|
|
6180
|
-
writeFixedPoint8(writer, bevel.highlightOpacity
|
|
6181
|
-
writeFixedPoint8(writer, bevel.shadowOpacity
|
|
6470
|
+
(0, psdWriter_1.writeUint8)(writer, style <= 0 ? bevelStyles.indexOf('inner bevel') : style); // reader defaults to inner bevel
|
|
6471
|
+
writeFixedPoint8(writer, (_j = bevel.highlightOpacity) !== null && _j !== void 0 ? _j : 1);
|
|
6472
|
+
writeFixedPoint8(writer, (_k = bevel.shadowOpacity) !== null && _k !== void 0 ? _k : 1);
|
|
6182
6473
|
(0, psdWriter_1.writeUint8)(writer, bevel.enabled ? 1 : 0);
|
|
6183
6474
|
(0, psdWriter_1.writeUint8)(writer, bevel.useGlobalLight ? 1 : 0);
|
|
6184
6475
|
(0, psdWriter_1.writeUint8)(writer, bevel.direction === 'down' ? 1 : 0);
|
|
@@ -6192,7 +6483,7 @@ function writeEffects(writer, effects) {
|
|
|
6192
6483
|
(0, psdWriter_1.writeUint32)(writer, 2);
|
|
6193
6484
|
writeBlendMode(writer, solidFill.blendMode);
|
|
6194
6485
|
(0, psdWriter_1.writeColor)(writer, solidFill.color);
|
|
6195
|
-
writeFixedPoint8(writer, solidFill.opacity
|
|
6486
|
+
writeFixedPoint8(writer, (_l = solidFill.opacity) !== null && _l !== void 0 ? _l : 1);
|
|
6196
6487
|
(0, psdWriter_1.writeUint8)(writer, solidFill.enabled ? 1 : 0);
|
|
6197
6488
|
(0, psdWriter_1.writeColor)(writer, solidFill.color);
|
|
6198
6489
|
}
|
|
@@ -6201,6 +6492,7 @@ function writeEffects(writer, effects) {
|
|
|
6201
6492
|
},{"./helpers":8,"./psdReader":13,"./psdWriter":14}],6:[function(require,module,exports){
|
|
6202
6493
|
"use strict";
|
|
6203
6494
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6495
|
+
exports.setProperty = setProperty;
|
|
6204
6496
|
exports.parseEngineData = parseEngineData;
|
|
6205
6497
|
exports.serializeEngineData = serializeEngineData;
|
|
6206
6498
|
function isWhitespace(char) {
|
|
@@ -6211,7 +6503,15 @@ function isNumber(char) {
|
|
|
6211
6503
|
// 0123456789.-
|
|
6212
6504
|
return (char >= 48 && char <= 57) || char === 46 || char === 45;
|
|
6213
6505
|
}
|
|
6214
|
-
function
|
|
6506
|
+
function setProperty(target, key, value) {
|
|
6507
|
+
if (key === '__proto__') { // avoid changing prototype of the object
|
|
6508
|
+
Object.defineProperty(target, key, { value, enumerable: true, configurable: true, writable: true });
|
|
6509
|
+
}
|
|
6510
|
+
else {
|
|
6511
|
+
target[key] = value;
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
function parseEngineData(data, reader) {
|
|
6215
6515
|
let index = 0;
|
|
6216
6516
|
function skipWhitespace() {
|
|
6217
6517
|
while (index < data.length && isWhitespace(data[index])) {
|
|
@@ -6270,7 +6570,8 @@ function parseEngineData(data) {
|
|
|
6270
6570
|
throw new Error('Invalid data');
|
|
6271
6571
|
const top = stack[stack.length - 1];
|
|
6272
6572
|
if (typeof top === 'string') {
|
|
6273
|
-
stack[stack.length - 2]
|
|
6573
|
+
const target = stack[stack.length - 2];
|
|
6574
|
+
setProperty(target, top, value);
|
|
6274
6575
|
pop();
|
|
6275
6576
|
}
|
|
6276
6577
|
else if (Array.isArray(top)) {
|
|
@@ -6284,7 +6585,8 @@ function parseEngineData(data) {
|
|
|
6284
6585
|
if (!stack.length)
|
|
6285
6586
|
pushContainer({});
|
|
6286
6587
|
const top = stack[stack.length - 1];
|
|
6287
|
-
if (
|
|
6588
|
+
if (typeof top === 'string' || Array.isArray(top)) {
|
|
6589
|
+
// name used as a value (either property value or array item)
|
|
6288
6590
|
if (name === 'nil') {
|
|
6289
6591
|
pushValue(null);
|
|
6290
6592
|
}
|
|
@@ -6306,6 +6608,8 @@ function parseEngineData(data) {
|
|
|
6306
6608
|
}
|
|
6307
6609
|
skipWhitespace();
|
|
6308
6610
|
let dataLength = data.length;
|
|
6611
|
+
let invalidTokens = 0;
|
|
6612
|
+
let firstInvalidToken = '';
|
|
6309
6613
|
while (dataLength > 0 && data[dataLength - 1] === 0)
|
|
6310
6614
|
dataLength--; // trim 0 bytes from end
|
|
6311
6615
|
while (index < dataLength) {
|
|
@@ -6365,14 +6669,16 @@ function parseEngineData(data) {
|
|
|
6365
6669
|
}
|
|
6366
6670
|
else {
|
|
6367
6671
|
index += 1;
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
);
|
|
6672
|
+
if (!invalidTokens)
|
|
6673
|
+
firstInvalidToken = `'${String.fromCharCode(char)}' (${char}) at ${index}`;
|
|
6674
|
+
invalidTokens++;
|
|
6372
6675
|
// throw new Error(`Invalid token ${String.fromCharCode(char)} at ${index}`);
|
|
6373
6676
|
}
|
|
6374
6677
|
skipWhitespace();
|
|
6375
6678
|
}
|
|
6679
|
+
if (invalidTokens) {
|
|
6680
|
+
reader.log(`Invalid tokens in engine data (${invalidTokens} in total, first: ${firstInvalidToken})`);
|
|
6681
|
+
}
|
|
6376
6682
|
return root;
|
|
6377
6683
|
}
|
|
6378
6684
|
const floatKeys = [
|
|
@@ -6382,7 +6688,6 @@ const floatKeys = [
|
|
|
6382
6688
|
'OutlineWidth', 'AutoLeading',
|
|
6383
6689
|
];
|
|
6384
6690
|
const intArrays = ['RunLengthArray'];
|
|
6385
|
-
// TODO: handle /nil
|
|
6386
6691
|
function serializeEngineData(data, condensed = false) {
|
|
6387
6692
|
let buffer = new Uint8Array(1024);
|
|
6388
6693
|
let offset = 0;
|
|
@@ -6418,16 +6723,21 @@ function serializeEngineData(data, condensed = false) {
|
|
|
6418
6723
|
if (!condensed)
|
|
6419
6724
|
writeString('\n');
|
|
6420
6725
|
}
|
|
6726
|
+
// NaN and Infinity can't be represented in engine data, write them as 0
|
|
6727
|
+
function finite(value) {
|
|
6728
|
+
return Number.isFinite(value) ? value : 0;
|
|
6729
|
+
}
|
|
6421
6730
|
function serializeInt(value) {
|
|
6422
|
-
return value.toString();
|
|
6731
|
+
return finite(value).toString();
|
|
6423
6732
|
}
|
|
6424
6733
|
function serializeFloat(value) {
|
|
6425
|
-
return value.toFixed(5)
|
|
6734
|
+
return finite(value).toFixed(5)
|
|
6426
6735
|
.replace(/(\d)0+$/g, '$1')
|
|
6427
6736
|
.replace(/^0+\.([1-9])/g, '.$1')
|
|
6428
6737
|
.replace(/^-0+\.0(\d)/g, '-.0$1');
|
|
6429
6738
|
}
|
|
6430
6739
|
function serializeNumber(value, key) {
|
|
6740
|
+
value = finite(value);
|
|
6431
6741
|
const isFloat = (key && floatKeys.indexOf(key) !== -1) || (value | 0) !== value;
|
|
6432
6742
|
return isFloat ? serializeFloat(value) : serializeInt(value);
|
|
6433
6743
|
}
|
|
@@ -6454,7 +6764,7 @@ function serializeEngineData(data, condensed = false) {
|
|
|
6454
6764
|
writeIndent();
|
|
6455
6765
|
}
|
|
6456
6766
|
}
|
|
6457
|
-
if (value === null) {
|
|
6767
|
+
if (value === null || value === undefined) { // undefined is only written for array items, properties are skipped
|
|
6458
6768
|
writePrefix();
|
|
6459
6769
|
writeString(condensed ? '/nil' : 'null');
|
|
6460
6770
|
}
|
|
@@ -6516,7 +6826,8 @@ function serializeEngineData(data, condensed = false) {
|
|
|
6516
6826
|
writeString('\n');
|
|
6517
6827
|
indent++;
|
|
6518
6828
|
for (const key of getKeys(value)) {
|
|
6519
|
-
|
|
6829
|
+
if (value[key] !== undefined)
|
|
6830
|
+
writeProperty(key, value[key]);
|
|
6520
6831
|
}
|
|
6521
6832
|
indent--;
|
|
6522
6833
|
writeIndent();
|
|
@@ -6527,7 +6838,8 @@ function serializeEngineData(data, condensed = false) {
|
|
|
6527
6838
|
if (condensed) {
|
|
6528
6839
|
if (typeof data === 'object') {
|
|
6529
6840
|
for (const key of getKeys(data)) {
|
|
6530
|
-
|
|
6841
|
+
if (data[key] !== undefined)
|
|
6842
|
+
writeProperty(key, data[key]);
|
|
6531
6843
|
}
|
|
6532
6844
|
}
|
|
6533
6845
|
}
|
|
@@ -6544,6 +6856,7 @@ function serializeEngineData(data, condensed = false) {
|
|
|
6544
6856
|
// /test/engineData2.json:1109 is character codes
|
|
6545
6857
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6546
6858
|
exports.decodeEngineData2 = decodeEngineData2;
|
|
6859
|
+
const engineData_1 = require("./engineData");
|
|
6547
6860
|
const keysColor = {
|
|
6548
6861
|
'0': {
|
|
6549
6862
|
uproot: true,
|
|
@@ -6914,48 +7227,78 @@ const keysRoot = {
|
|
|
6914
7227
|
},
|
|
6915
7228
|
},
|
|
6916
7229
|
};
|
|
6917
|
-
|
|
7230
|
+
const MAX_DEPTH = 256;
|
|
7231
|
+
function getKey(keys, key) {
|
|
7232
|
+
return Object.prototype.hasOwnProperty.call(keys, key) ? keys[key] : undefined;
|
|
7233
|
+
}
|
|
7234
|
+
function decodeObj(obj, keys, depth) {
|
|
6918
7235
|
var _a, _b;
|
|
6919
|
-
if (
|
|
7236
|
+
if (depth > MAX_DEPTH)
|
|
7237
|
+
throw new Error(`Engine data is nested too deeply (more than ${MAX_DEPTH} levels)`);
|
|
7238
|
+
if (obj === null || obj === undefined)
|
|
6920
7239
|
return obj;
|
|
6921
7240
|
if (Array.isArray(obj))
|
|
6922
|
-
return obj.map(x => decodeObj(x, keys));
|
|
7241
|
+
return obj.map(x => decodeObj(x, keys, depth + 1));
|
|
6923
7242
|
if (typeof obj !== 'object')
|
|
6924
7243
|
return obj;
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
7244
|
+
const objKeys = Object.keys(obj);
|
|
7245
|
+
const uprootKey = objKeys.find(key => { var _a; return key !== '99' && ((_a = getKey(keys, key)) === null || _a === void 0 ? void 0 : _a.uproot); });
|
|
7246
|
+
let result;
|
|
7247
|
+
if (uprootKey !== undefined) {
|
|
7248
|
+
// replace the object with the value of the uprooted key
|
|
7249
|
+
result = decodeObj(obj[uprootKey], (_a = getKey(keys, uprootKey).children) !== null && _a !== void 0 ? _a : {}, depth + 1);
|
|
7250
|
+
// primitive values can't hold extra properties (type and sibling keys are dropped)
|
|
7251
|
+
if (result === null || typeof result !== 'object')
|
|
7252
|
+
return result;
|
|
7253
|
+
if (obj['99'])
|
|
7254
|
+
result._type = obj['99'];
|
|
7255
|
+
if (Array.isArray(result))
|
|
7256
|
+
return result;
|
|
7257
|
+
}
|
|
7258
|
+
else {
|
|
7259
|
+
result = {};
|
|
7260
|
+
}
|
|
7261
|
+
for (const key of objKeys) {
|
|
7262
|
+
if (key === uprootKey)
|
|
7263
|
+
continue;
|
|
7264
|
+
const info = getKey(keys, key);
|
|
7265
|
+
if (key === '99') {
|
|
7266
|
+
if (uprootKey === undefined)
|
|
7267
|
+
result._type = obj[key];
|
|
6941
7268
|
}
|
|
6942
7269
|
else {
|
|
6943
|
-
|
|
7270
|
+
const name = (info === null || info === void 0 ? void 0 : info.name) || key;
|
|
7271
|
+
// don't overwrite fields of uprooted object with sibling keys
|
|
7272
|
+
if (uprootKey === undefined || !(name in result)) {
|
|
7273
|
+
(0, engineData_1.setProperty)(result, name, decodeObj(obj[key], (_b = info === null || info === void 0 ? void 0 : info.children) !== null && _b !== void 0 ? _b : {}, depth + 1));
|
|
7274
|
+
}
|
|
6944
7275
|
}
|
|
6945
7276
|
}
|
|
6946
7277
|
return result;
|
|
6947
7278
|
}
|
|
7279
|
+
function emptyResourceDict() {
|
|
7280
|
+
return { FontSet: [], StyleSheetSet: [], ParagraphSheetSet: [] };
|
|
7281
|
+
}
|
|
6948
7282
|
function decodeEngineData2(data) {
|
|
6949
|
-
|
|
7283
|
+
const result = decodeObj(data, keysRoot, 0);
|
|
7284
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) {
|
|
7285
|
+
return { ResourceDict: emptyResourceDict(), EngineDict: {} };
|
|
7286
|
+
}
|
|
7287
|
+
if (!result.ResourceDict || typeof result.ResourceDict !== 'object') {
|
|
7288
|
+
result.ResourceDict = emptyResourceDict();
|
|
7289
|
+
}
|
|
7290
|
+
return result;
|
|
6950
7291
|
}
|
|
6951
7292
|
|
|
6952
|
-
},{}],8:[function(require,module,exports){
|
|
7293
|
+
},{"./engineData":6}],8:[function(require,module,exports){
|
|
6953
7294
|
"use strict";
|
|
6954
7295
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6955
7296
|
exports.createImageData = exports.createCanvas = exports.MaskParams = exports.LayerMaskFlags = exports.ColorSpace = exports.largeAdditionalInfoKeys = exports.layerColors = exports.toBlendMode = exports.fromBlendMode = exports.RAW_IMAGE_DATA = exports.MOCK_HANDLERS = void 0;
|
|
6956
7297
|
exports.revMap = revMap;
|
|
6957
7298
|
exports.createEnum = createEnum;
|
|
6958
7299
|
exports.offsetForChannel = offsetForChannel;
|
|
7300
|
+
exports.normalizeLabAB = normalizeLabAB;
|
|
7301
|
+
exports.denormalizeLabAB = denormalizeLabAB;
|
|
6959
7302
|
exports.clamp = clamp;
|
|
6960
7303
|
exports.hasAlpha = hasAlpha;
|
|
6961
7304
|
exports.resetImageData = resetImageData;
|
|
@@ -7075,6 +7418,13 @@ function offsetForChannel(channelId, cmyk) {
|
|
|
7075
7418
|
default: return channelId + 1;
|
|
7076
7419
|
}
|
|
7077
7420
|
}
|
|
7421
|
+
// Lab a/b components are stored in -128..127 range (multiplied by scale), normalized values are in -1..1 range
|
|
7422
|
+
function normalizeLabAB(value, scale = 1) {
|
|
7423
|
+
return value < 0 ? (value / (128 * scale)) : (value / (127 * scale));
|
|
7424
|
+
}
|
|
7425
|
+
function denormalizeLabAB(value, scale = 1) {
|
|
7426
|
+
return value < 0 ? (value * (128 * scale)) : (value * (127 * scale));
|
|
7427
|
+
}
|
|
7078
7428
|
function clamp(value, min, max) {
|
|
7079
7429
|
return value < min ? min : (value > max ? max : value);
|
|
7080
7430
|
}
|
|
@@ -7150,9 +7500,10 @@ function writeDataRaw(data, offset, width, height) {
|
|
|
7150
7500
|
}
|
|
7151
7501
|
return array;
|
|
7152
7502
|
}
|
|
7503
|
+
// returns view into the buffer, the buffer has to fit worst case size (see getRLEChannelBound), throws if it doesn't
|
|
7153
7504
|
function writeDataRLE(buffer, { data, width, height }, offsets, large) {
|
|
7154
7505
|
if (!width || !height)
|
|
7155
|
-
return
|
|
7506
|
+
return buffer.subarray(0, 0);
|
|
7156
7507
|
const stride = (4 * width) | 0;
|
|
7157
7508
|
let ol = 0;
|
|
7158
7509
|
let o = (offsets.length * (large ? 4 : 2) * height) | 0;
|
|
@@ -7229,6 +7580,9 @@ function writeDataRLE(buffer, { data, width, height }, offsets, large) {
|
|
|
7229
7580
|
buffer[o++] = data[p];
|
|
7230
7581
|
}
|
|
7231
7582
|
}
|
|
7583
|
+
// writes past the end of typed array are ignored, so it's enough to check the size after each row
|
|
7584
|
+
if (o > buffer.length)
|
|
7585
|
+
throw new Error(`RLE buffer too small (${buffer.length})`);
|
|
7232
7586
|
const length = o - startOffset;
|
|
7233
7587
|
if (large) {
|
|
7234
7588
|
buffer[ol++] = (length >> 24) & 0xff;
|
|
@@ -7238,7 +7592,8 @@ function writeDataRLE(buffer, { data, width, height }, offsets, large) {
|
|
|
7238
7592
|
buffer[ol++] = length & 0xff;
|
|
7239
7593
|
}
|
|
7240
7594
|
}
|
|
7241
|
-
|
|
7595
|
+
// returns view of the buffer, copy the data if the buffer is going to be reused
|
|
7596
|
+
return buffer.subarray(0, o);
|
|
7242
7597
|
}
|
|
7243
7598
|
function writeDataZipWithoutPrediction({ data, width, height }, offsets) {
|
|
7244
7599
|
const size = width * height;
|
|
@@ -7266,7 +7621,7 @@ function writeDataZipWithoutPrediction({ data, width, height }, offsets) {
|
|
|
7266
7621
|
return buffers[0];
|
|
7267
7622
|
}
|
|
7268
7623
|
}
|
|
7269
|
-
function createCanvasFromData(data) {
|
|
7624
|
+
function createCanvasFromData(data, reader) {
|
|
7270
7625
|
const canvas = (0, exports.createCanvas)(100, 100);
|
|
7271
7626
|
try {
|
|
7272
7627
|
const context = canvas.getContext('2d');
|
|
@@ -7276,7 +7631,7 @@ function createCanvasFromData(data) {
|
|
|
7276
7631
|
context.putImageData(imageData, 0, 0);
|
|
7277
7632
|
}
|
|
7278
7633
|
catch (e) {
|
|
7279
|
-
|
|
7634
|
+
reader.log('JPEG decompression error', e.message);
|
|
7280
7635
|
}
|
|
7281
7636
|
return canvas;
|
|
7282
7637
|
}
|
|
@@ -7343,6 +7698,18 @@ function writeUtf8String(writer, value) {
|
|
|
7343
7698
|
const buffer = (0, utf8_1.encodeString)(value);
|
|
7344
7699
|
(0, psdWriter_1.writeBytes)(writer, buffer);
|
|
7345
7700
|
}
|
|
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
|
+
}
|
|
7346
7713
|
function readEncodedString(reader) {
|
|
7347
7714
|
const length = (0, psdReader_1.readUint8)(reader);
|
|
7348
7715
|
const buffer = (0, psdReader_1.readBytes)(reader, length);
|
|
@@ -7354,19 +7721,26 @@ function readEncodedString(reader) {
|
|
|
7354
7721
|
}
|
|
7355
7722
|
}
|
|
7356
7723
|
if (notAscii) {
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7724
|
+
const decoder = getGbkDecoder();
|
|
7725
|
+
if (decoder) {
|
|
7726
|
+
try {
|
|
7727
|
+
return decoder.decode(buffer);
|
|
7728
|
+
}
|
|
7729
|
+
catch (_a) { }
|
|
7360
7730
|
}
|
|
7361
|
-
catch (_a) { }
|
|
7362
7731
|
}
|
|
7363
7732
|
return (0, utf8_1.decodeString)(buffer);
|
|
7364
7733
|
}
|
|
7365
7734
|
function writeEncodedString(writer, value) {
|
|
7366
7735
|
let ascii = '';
|
|
7367
|
-
for (let i = 0
|
|
7368
|
-
|
|
7736
|
+
for (let i = 0; i < value.length;) {
|
|
7737
|
+
const code = value.codePointAt(i);
|
|
7738
|
+
ascii += code > 0x7f ? '?' : String.fromCharCode(code);
|
|
7739
|
+
i += code > 0xffff ? 2 : 1; // skip low surrogate of astral characters
|
|
7369
7740
|
}
|
|
7741
|
+
// length is stored in a single byte
|
|
7742
|
+
if (ascii.length > 255)
|
|
7743
|
+
ascii = ascii.substring(0, 255);
|
|
7370
7744
|
const buffer = (0, utf8_1.encodeString)(ascii);
|
|
7371
7745
|
(0, psdWriter_1.writeUint8)(writer, buffer.byteLength);
|
|
7372
7746
|
(0, psdWriter_1.writeBytes)(writer, buffer);
|
|
@@ -7707,7 +8081,7 @@ addHandler(1032, target => target.gridAndGuidesInformation !== undefined, (reade
|
|
|
7707
8081
|
};
|
|
7708
8082
|
for (let i = 0; i < count; i++) {
|
|
7709
8083
|
target.gridAndGuidesInformation.guides.push({
|
|
7710
|
-
location: (0, psdReader_1.
|
|
8084
|
+
location: (0, psdReader_1.readInt32)(reader) / 32,
|
|
7711
8085
|
direction: (0, psdReader_1.readUint8)(reader) ? 'horizontal' : 'vertical'
|
|
7712
8086
|
});
|
|
7713
8087
|
}
|
|
@@ -7716,11 +8090,11 @@ addHandler(1032, target => target.gridAndGuidesInformation !== undefined, (reade
|
|
|
7716
8090
|
const grid = info.grid || { horizontal: 18 * 32, vertical: 18 * 32 };
|
|
7717
8091
|
const guides = info.guides || [];
|
|
7718
8092
|
(0, psdWriter_1.writeUint32)(writer, 1);
|
|
7719
|
-
(0, psdWriter_1.writeUint32)(writer, grid.horizontal);
|
|
7720
|
-
(0, psdWriter_1.writeUint32)(writer, grid.vertical);
|
|
8093
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round(grid.horizontal));
|
|
8094
|
+
(0, psdWriter_1.writeUint32)(writer, Math.round(grid.vertical));
|
|
7721
8095
|
(0, psdWriter_1.writeUint32)(writer, guides.length);
|
|
7722
8096
|
for (const g of guides) {
|
|
7723
|
-
(0, psdWriter_1.
|
|
8097
|
+
(0, psdWriter_1.writeInt32)(writer, Math.round(g.location * 32));
|
|
7724
8098
|
(0, psdWriter_1.writeUint8)(writer, g.direction === 'horizontal' ? 1 : 0);
|
|
7725
8099
|
}
|
|
7726
8100
|
});
|
|
@@ -7736,10 +8110,10 @@ target => target.layerComps !== undefined, (reader, target) => {
|
|
|
7736
8110
|
name: item['Nm '],
|
|
7737
8111
|
capturedInfo: item.capturedInfo,
|
|
7738
8112
|
});
|
|
7739
|
-
if (
|
|
8113
|
+
if (item.comment !== undefined)
|
|
7740
8114
|
target.layerComps.list[target.layerComps.list.length - 1].comment = item.comment;
|
|
7741
8115
|
}
|
|
7742
|
-
if (
|
|
8116
|
+
if (desc.lastAppliedComp !== undefined)
|
|
7743
8117
|
target.layerComps.lastApplied = desc.lastAppliedComp;
|
|
7744
8118
|
}, (writer, target) => {
|
|
7745
8119
|
const layerComps = target.layerComps;
|
|
@@ -7748,13 +8122,13 @@ target => target.layerComps !== undefined, (reader, target) => {
|
|
|
7748
8122
|
const t = {};
|
|
7749
8123
|
t._classID = 'Comp';
|
|
7750
8124
|
t['Nm '] = item.name;
|
|
7751
|
-
if (
|
|
8125
|
+
if (item.comment !== undefined)
|
|
7752
8126
|
t.comment = item.comment;
|
|
7753
8127
|
t.compID = item.id;
|
|
7754
8128
|
t.capturedInfo = item.capturedInfo;
|
|
7755
8129
|
desc.list.push(t);
|
|
7756
8130
|
}
|
|
7757
|
-
if (
|
|
8131
|
+
if (layerComps.lastApplied !== undefined)
|
|
7758
8132
|
desc.lastAppliedComp = layerComps.lastApplied;
|
|
7759
8133
|
// console.log('CompList', require('util').inspect(desc, false, 99, true));
|
|
7760
8134
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'CompList', desc);
|
|
@@ -7796,8 +8170,8 @@ target => target.onionSkins !== undefined, (reader, target) => {
|
|
|
7796
8170
|
numBefore: onionSkins.framesBefore,
|
|
7797
8171
|
numAfter: onionSkins.framesAfter,
|
|
7798
8172
|
Spcn: onionSkins.frameSpacing,
|
|
7799
|
-
minOpacity: (onionSkins.minOpacity * 100)
|
|
7800
|
-
maxOpacity: (onionSkins.maxOpacity * 100)
|
|
8173
|
+
minOpacity: Math.round(onionSkins.minOpacity * 100),
|
|
8174
|
+
maxOpacity: Math.round(onionSkins.maxOpacity * 100),
|
|
7801
8175
|
BlnM: Math.max(0, onionSkinsBlendModes.indexOf(onionSkins.blendMode)),
|
|
7802
8176
|
};
|
|
7803
8177
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
@@ -7858,7 +8232,7 @@ target => target.timelineInformation !== undefined, (reader, target) => {
|
|
|
7858
8232
|
LCnt: timeline.repeats,
|
|
7859
8233
|
globalTrackList: (0, descriptor_1.serializeTrackList)(timeline.globalTracks),
|
|
7860
8234
|
audioClipGroupList: {
|
|
7861
|
-
audioClipGroupList: (_a = timeline.audioClipGroups)
|
|
8235
|
+
audioClipGroupList: ((_a = timeline.audioClipGroups) !== null && _a !== void 0 ? _a : []).map(a => ({
|
|
7862
8236
|
groupID: a.id,
|
|
7863
8237
|
muted: a.muted,
|
|
7864
8238
|
audioClipList: a.audioClips.map(c => ({
|
|
@@ -8001,8 +8375,13 @@ target => target.slices ? target.slices.length : 0, (reader, target, leftBytes)
|
|
|
8001
8375
|
}
|
|
8002
8376
|
if (leftBytes()) {
|
|
8003
8377
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
8378
|
+
const slicesById = new Map();
|
|
8379
|
+
for (const s of slices) {
|
|
8380
|
+
if (!slicesById.has(s.id))
|
|
8381
|
+
slicesById.set(s.id, s);
|
|
8382
|
+
}
|
|
8004
8383
|
desc.slices.forEach(d => {
|
|
8005
|
-
const slice =
|
|
8384
|
+
const slice = slicesById.get(d.sliceID);
|
|
8006
8385
|
if (slice) {
|
|
8007
8386
|
slice.topOutset = d.topOutset;
|
|
8008
8387
|
slice.leftOutset = d.leftOutset;
|
|
@@ -8129,7 +8508,7 @@ addHandler(1036, target => target.thumbnail !== undefined || target.thumbnailRaw
|
|
|
8129
8508
|
target.thumbnailRaw = { width, height, data };
|
|
8130
8509
|
}
|
|
8131
8510
|
else if (data.byteLength) {
|
|
8132
|
-
target.thumbnail = (0, helpers_1.createCanvasFromData)(data);
|
|
8511
|
+
target.thumbnail = (0, helpers_1.createCanvasFromData)(data, reader);
|
|
8133
8512
|
}
|
|
8134
8513
|
}, (writer, target) => {
|
|
8135
8514
|
var _a;
|
|
@@ -8208,7 +8587,7 @@ addHandler(1088, target => target.pathSelectionState !== undefined, (reader, tar
|
|
|
8208
8587
|
const desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
|
|
8209
8588
|
target.pathSelectionState = desc['null'];
|
|
8210
8589
|
}, (writer, target) => {
|
|
8211
|
-
const desc = { 'null': target.pathSelectionState };
|
|
8590
|
+
const desc = { 'null': (0, descriptor_1.pathSelectionStateToReference)(target.pathSelectionState) };
|
|
8212
8591
|
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
|
|
8213
8592
|
});
|
|
8214
8593
|
helpers_1.MOCK_HANDLERS && addHandler(1025, target => target._ir1025 !== undefined, (reader, target, left) => {
|
|
@@ -8290,7 +8669,7 @@ target => target.animations !== undefined, (reader, target, left) => {
|
|
|
8290
8669
|
FrID: f.id,
|
|
8291
8670
|
};
|
|
8292
8671
|
if (f.delay)
|
|
8293
|
-
frame.FrDl = (f.delay * 100)
|
|
8672
|
+
frame.FrDl = Math.round(f.delay * 100);
|
|
8294
8673
|
frame.FrDs = FrmD.encode(f.dispose);
|
|
8295
8674
|
// if (i === 0) frame.FrGA = 30; // ???
|
|
8296
8675
|
desc.FrIn.push(frame);
|
|
@@ -8414,6 +8793,7 @@ function writePsdBuffer(psd, options) {
|
|
|
8414
8793
|
if (typeof Buffer === 'undefined') {
|
|
8415
8794
|
throw new Error('Buffer not supported on this platform');
|
|
8416
8795
|
}
|
|
8796
|
+
// copy, so the buffer doesn't hold on to the unused part of the writer's buffer
|
|
8417
8797
|
return Buffer.from(writePsdUint8Array(psd, options));
|
|
8418
8798
|
}
|
|
8419
8799
|
|
|
@@ -8467,6 +8847,8 @@ const maxResolutionInMP = 100; // Don't decode more than 100 megapixels
|
|
|
8467
8847
|
const maxMemoryUsageBytes = 64 * 1024 * 1024; // Don't decode if memory footprint is more than 64MB
|
|
8468
8848
|
let totalBytesAllocated = 0; // avoid unexpected OOMs from untrusted content.
|
|
8469
8849
|
function requestMemoryAllocation(increaseAmount) {
|
|
8850
|
+
if (!isFinite(increaseAmount) || increaseAmount < 0)
|
|
8851
|
+
throw new Error(`Invalid memory allocation size (${increaseAmount})`);
|
|
8470
8852
|
const totalMemoryImpactBytes = totalBytesAllocated + increaseAmount;
|
|
8471
8853
|
if (totalMemoryImpactBytes > maxMemoryUsageBytes) {
|
|
8472
8854
|
const exceededAmount = Math.ceil((totalMemoryImpactBytes - maxMemoryUsageBytes) / 1024 / 1024);
|
|
@@ -8532,6 +8914,8 @@ function decodeScan(data, offset, frame, components, resetInterval, spectralStar
|
|
|
8532
8914
|
return bitsData >>> 7;
|
|
8533
8915
|
}
|
|
8534
8916
|
function decodeHuffman(tree) {
|
|
8917
|
+
if (!tree)
|
|
8918
|
+
throw new Error('Missing Huffman table');
|
|
8535
8919
|
let node = tree;
|
|
8536
8920
|
while (true) {
|
|
8537
8921
|
node = node[readBit()];
|
|
@@ -8714,6 +9098,8 @@ function decodeScan(data, offset, frame, components, resetInterval, spectralStar
|
|
|
8714
9098
|
else {
|
|
8715
9099
|
mcuExpected = mcusPerLine * frame.mcusPerColumn;
|
|
8716
9100
|
}
|
|
9101
|
+
if (!isFinite(mcuExpected) || mcuExpected < 0)
|
|
9102
|
+
throw new Error('Invalid number of MCUs');
|
|
8717
9103
|
if (!resetInterval)
|
|
8718
9104
|
resetInterval = mcuExpected;
|
|
8719
9105
|
let h;
|
|
@@ -8729,6 +9115,9 @@ function decodeScan(data, offset, frame, components, resetInterval, spectralStar
|
|
|
8729
9115
|
for (let n = 0; n < resetInterval; n++) {
|
|
8730
9116
|
decodeBlock(component, decodeFn, mcu);
|
|
8731
9117
|
mcu++;
|
|
9118
|
+
// If we've reached our expected MCU's, stop decoding
|
|
9119
|
+
if (mcu === mcuExpected)
|
|
9120
|
+
break;
|
|
8732
9121
|
}
|
|
8733
9122
|
}
|
|
8734
9123
|
else {
|
|
@@ -8789,6 +9178,8 @@ function buildComponentData(component) {
|
|
|
8789
9178
|
// 988-991.
|
|
8790
9179
|
function quantizeAndInverse(zz, dataOut, dataIn) {
|
|
8791
9180
|
const qt = component.quantizationTable;
|
|
9181
|
+
if (!qt)
|
|
9182
|
+
throw new Error('Missing quantization table');
|
|
8792
9183
|
const p = dataIn;
|
|
8793
9184
|
// dequant
|
|
8794
9185
|
for (let i = 0; i < 64; i++) {
|
|
@@ -9138,10 +9529,14 @@ function parse(data) {
|
|
|
9138
9529
|
throw new Error(`maxResolutionInMP limit exceeded by ${exceededAmount}MP`);
|
|
9139
9530
|
}
|
|
9140
9531
|
const componentsCount = data[offset++];
|
|
9532
|
+
if (!componentsCount)
|
|
9533
|
+
throw new Error('SOF: no components in frame');
|
|
9141
9534
|
for (let i = 0; i < componentsCount; i++) {
|
|
9142
9535
|
const componentId = data[offset];
|
|
9143
9536
|
const h = data[offset + 1] >> 4;
|
|
9144
9537
|
const v = data[offset + 1] & 15;
|
|
9538
|
+
if (h < 1 || h > 4 || v < 1 || v > 4)
|
|
9539
|
+
throw new Error(`SOF: invalid sampling factors (${h}x${v})`);
|
|
9145
9540
|
const qId = data[offset + 2];
|
|
9146
9541
|
frame.componentsOrder.push(componentId);
|
|
9147
9542
|
frame.components[componentId] = {
|
|
@@ -9189,11 +9584,16 @@ function parse(data) {
|
|
|
9189
9584
|
readUint16(); // Ignore this data since it represents the image height
|
|
9190
9585
|
break;
|
|
9191
9586
|
case 0xFFDA: { // SOS (Start of Scan)
|
|
9587
|
+
if (!frame)
|
|
9588
|
+
throw new Error('SOS: scan before frame header (SOF)');
|
|
9192
9589
|
readUint16(); // skip data length
|
|
9193
9590
|
const selectorsCount = data[offset++];
|
|
9194
9591
|
const components = [];
|
|
9195
9592
|
for (let i = 0; i < selectorsCount; i++) {
|
|
9196
|
-
const
|
|
9593
|
+
const componentId = data[offset++];
|
|
9594
|
+
const component = frame.components[componentId];
|
|
9595
|
+
if (!component)
|
|
9596
|
+
throw new Error(`SOS: component ${componentId} not found in frame`);
|
|
9197
9597
|
const tableSpec = data[offset++];
|
|
9198
9598
|
component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
|
|
9199
9599
|
component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
|
|
@@ -9242,7 +9642,10 @@ function parse(data) {
|
|
|
9242
9642
|
for (let i = 0; i < frames.length; i++) {
|
|
9243
9643
|
const cp = frames[i].components;
|
|
9244
9644
|
for (let j in cp) { // TODO: don't use `in`
|
|
9245
|
-
|
|
9645
|
+
const table = quantizationTables[cp[j].quantizationIdx];
|
|
9646
|
+
if (!table)
|
|
9647
|
+
throw new Error(`Missing quantization table ${cp[j].quantizationIdx}`);
|
|
9648
|
+
cp[j].quantizationTable = table;
|
|
9246
9649
|
delete cp[j].quantizationIdx; // TODO: why ???
|
|
9247
9650
|
}
|
|
9248
9651
|
}
|
|
@@ -9298,11 +9701,8 @@ function getData(decoded) {
|
|
|
9298
9701
|
break;
|
|
9299
9702
|
}
|
|
9300
9703
|
case 3: {
|
|
9301
|
-
// The default transform for three components is true
|
|
9302
|
-
colorTransform = true;
|
|
9303
|
-
// The adobe transform marker overrides any previous setting
|
|
9304
|
-
if (decoded.adobe && decoded.adobe.transformCode)
|
|
9305
|
-
colorTransform = true;
|
|
9704
|
+
// The default transform for three components is true, the adobe transform marker overrides it
|
|
9705
|
+
colorTransform = decoded.adobe ? !!decoded.adobe.transformCode : true;
|
|
9306
9706
|
const component1 = decoded.components[0];
|
|
9307
9707
|
const component2 = decoded.components[1];
|
|
9308
9708
|
const component3 = decoded.components[2];
|
|
@@ -9629,22 +10029,24 @@ function readFixedPoint32(reader) {
|
|
|
9629
10029
|
function readFixedPointPath32(reader) {
|
|
9630
10030
|
return readInt32(reader) / (1 << 24);
|
|
9631
10031
|
}
|
|
10032
|
+
// NOTE: returned array may alias the reader's underlying buffer, never write into it
|
|
9632
10033
|
function readBytes(reader, length) {
|
|
9633
|
-
const start = reader.
|
|
10034
|
+
const start = reader.offset;
|
|
10035
|
+
const viewLength = reader.view.byteLength;
|
|
9634
10036
|
reader.offset += length;
|
|
9635
|
-
if ((start + length) >
|
|
10037
|
+
if ((start + length) > viewLength) {
|
|
9636
10038
|
// fix for broken PSD files that are missing part of file at the end
|
|
9637
10039
|
warnOrThrow(reader, 'Reading bytes exceeding buffer length');
|
|
9638
10040
|
if (length > (100 * 1024 * 1024))
|
|
9639
10041
|
throw new Error('Reading past end of file'); // limit to 100MB
|
|
9640
10042
|
const result = new Uint8Array(length);
|
|
9641
|
-
const len = Math.min(length,
|
|
10043
|
+
const len = Math.min(length, viewLength - start);
|
|
9642
10044
|
if (len > 0)
|
|
9643
|
-
result.set(new Uint8Array(reader.view.buffer, start, len));
|
|
10045
|
+
result.set(new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, len));
|
|
9644
10046
|
return result;
|
|
9645
10047
|
}
|
|
9646
10048
|
else {
|
|
9647
|
-
return new Uint8Array(reader.view.buffer, start, length);
|
|
10049
|
+
return new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, length);
|
|
9648
10050
|
}
|
|
9649
10051
|
}
|
|
9650
10052
|
function readSignature(reader) {
|
|
@@ -9669,31 +10071,52 @@ function readUnicodeString(reader) {
|
|
|
9669
10071
|
const length = readUint32(reader);
|
|
9670
10072
|
return readUnicodeStringWithLength(reader, length);
|
|
9671
10073
|
}
|
|
9672
|
-
|
|
10074
|
+
const STRING_CHUNK_SIZE = 0x2000;
|
|
10075
|
+
function checkReadBounds(reader, size) {
|
|
10076
|
+
if (reader.offset < 0 || (reader.offset + size) > reader.view.byteLength) {
|
|
10077
|
+
throw new RangeError('Offset is outside the bounds of the DataView');
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10080
|
+
function readUtf16String(reader, length, littleEndian) {
|
|
10081
|
+
if (!(length > 0))
|
|
10082
|
+
return '';
|
|
10083
|
+
checkReadBounds(reader, length * 2);
|
|
10084
|
+
const view = reader.view;
|
|
10085
|
+
const codes = new Uint16Array(Math.min(length, STRING_CHUNK_SIZE));
|
|
10086
|
+
let offset = reader.offset;
|
|
9673
10087
|
let text = '';
|
|
9674
|
-
|
|
9675
|
-
const
|
|
9676
|
-
|
|
9677
|
-
|
|
10088
|
+
for (let i = 0; i < length; i += STRING_CHUNK_SIZE) {
|
|
10089
|
+
const count = Math.min(STRING_CHUNK_SIZE, length - i);
|
|
10090
|
+
for (let j = 0; j < count; j++, offset += 2) {
|
|
10091
|
+
codes[j] = view.getUint16(offset, littleEndian);
|
|
9678
10092
|
}
|
|
10093
|
+
text += String.fromCharCode.apply(null, (count === codes.length ? codes : codes.subarray(0, count)));
|
|
9679
10094
|
}
|
|
10095
|
+
reader.offset = offset;
|
|
10096
|
+
// remove trailing \0
|
|
10097
|
+
if (text.charCodeAt(text.length - 1) === 0)
|
|
10098
|
+
text = text.substring(0, text.length - 1);
|
|
9680
10099
|
return text;
|
|
9681
10100
|
}
|
|
9682
|
-
function
|
|
10101
|
+
function bytesToString(bytes) {
|
|
9683
10102
|
let text = '';
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
if (value || length > 0) { // remove trailing \0
|
|
9687
|
-
text += String.fromCharCode(value);
|
|
9688
|
-
}
|
|
10103
|
+
for (let i = 0; i < bytes.length; i += STRING_CHUNK_SIZE) {
|
|
10104
|
+
text += String.fromCharCode.apply(null, bytes.subarray(i, i + STRING_CHUNK_SIZE));
|
|
9689
10105
|
}
|
|
9690
10106
|
return text;
|
|
9691
10107
|
}
|
|
10108
|
+
function readUnicodeStringWithLength(reader, length) {
|
|
10109
|
+
return readUtf16String(reader, length, false);
|
|
10110
|
+
}
|
|
10111
|
+
function readUnicodeStringWithLengthLE(reader, length) {
|
|
10112
|
+
return readUtf16String(reader, length, true);
|
|
10113
|
+
}
|
|
9692
10114
|
function readAsciiString(reader, length) {
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
10115
|
+
if (!(length > 0))
|
|
10116
|
+
return '';
|
|
10117
|
+
checkReadBounds(reader, length);
|
|
10118
|
+
const text = bytesToString(new Uint8Array(reader.view.buffer, reader.view.byteOffset + reader.offset, length));
|
|
10119
|
+
reader.offset += length;
|
|
9697
10120
|
return text;
|
|
9698
10121
|
}
|
|
9699
10122
|
function skipBytes(reader, count) {
|
|
@@ -9707,12 +10130,7 @@ function checkSignature(reader, a, b) {
|
|
|
9707
10130
|
}
|
|
9708
10131
|
}
|
|
9709
10132
|
function readShortString(reader, length) {
|
|
9710
|
-
|
|
9711
|
-
let result = '';
|
|
9712
|
-
for (let i = 0; i < buffer.length; i++) {
|
|
9713
|
-
result += String.fromCharCode(buffer[i]);
|
|
9714
|
-
}
|
|
9715
|
-
return result;
|
|
10133
|
+
return bytesToString(readBytes(reader, length));
|
|
9716
10134
|
}
|
|
9717
10135
|
function isValidSignature(sig) {
|
|
9718
10136
|
return sig === '8BIM' || sig === 'MeSa' || sig === 'AgHg' || sig === 'PHUT' || sig === 'DCSR';
|
|
@@ -9733,7 +10151,7 @@ function readPsd(reader, readOptions = {}) {
|
|
|
9733
10151
|
const maxSize = version === 1 ? 30000 : 300000;
|
|
9734
10152
|
if (width > maxSize || height > maxSize)
|
|
9735
10153
|
throw new Error(`Invalid size: ${width}x${height}`);
|
|
9736
|
-
if (channels >
|
|
10154
|
+
if (channels < 1 || channels > 56)
|
|
9737
10155
|
throw new Error(`Invalid channel count: ${channels}`);
|
|
9738
10156
|
if (![1, 8, 16, 32].includes(bitsPerChannel))
|
|
9739
10157
|
throw new Error(`Invalid bitsPerChannel: ${bitsPerChannel}`);
|
|
@@ -9835,7 +10253,10 @@ function readPsd(reader, readOptions = {}) {
|
|
|
9835
10253
|
const skipComposite = reader.skipCompositeImageData && (reader.skipLayerImageData || hasChildren);
|
|
9836
10254
|
if (!skipComposite) {
|
|
9837
10255
|
if (reader.useRawData) {
|
|
9838
|
-
|
|
10256
|
+
const rawOffset = Math.min(reader.offset, reader.view.byteLength);
|
|
10257
|
+
const rawCompositeData = new Uint8Array(reader.view.buffer, reader.view.byteOffset + rawOffset, reader.view.byteLength - rawOffset);
|
|
10258
|
+
psd.rawCompositeData = rawCompositeData;
|
|
10259
|
+
psd.rawCompositeDataInfo = { large: reader.large, globalAlpha: reader.globalAlpha };
|
|
9839
10260
|
}
|
|
9840
10261
|
else {
|
|
9841
10262
|
const imageData = readImageData(reader, psd);
|
|
@@ -9890,7 +10311,9 @@ function readLayerInfo(reader, psd, imageResources) {
|
|
|
9890
10311
|
stack.push(l);
|
|
9891
10312
|
}
|
|
9892
10313
|
else if (type === 3 /* SectionDividerType.BoundingSectionDivider */) {
|
|
9893
|
-
|
|
10314
|
+
// ignore unmatched section dividers, never pop the root
|
|
10315
|
+
if (stack.length > 1)
|
|
10316
|
+
stack.pop();
|
|
9894
10317
|
// this was workaround because I didn't know what `lsdk` section was, now it's probably not needed anymore
|
|
9895
10318
|
// } else if (l.name === '</Layer group>' && !l.sectionDivider && !l.top && !l.left && !l.bottom && !l.right) {
|
|
9896
10319
|
// // sometimes layer group terminator doesn't have sectionDivider, so we just guess here (PS bug ?)
|
|
@@ -9976,7 +10399,7 @@ function readLayerMaskData(reader, layer) {
|
|
|
9976
10399
|
mask.positionRelativeToLayer = (flags & 1 /* LayerMaskFlags.PositionRelativeToLayer */) !== 0;
|
|
9977
10400
|
mask.disabled = (flags & 2 /* LayerMaskFlags.LayerMaskDisabled */) !== 0;
|
|
9978
10401
|
mask.fromVectorData = (flags & 8 /* LayerMaskFlags.LayerMaskFromRenderingOtherData */) !== 0;
|
|
9979
|
-
if (
|
|
10402
|
+
if (hasRealMaskData(reader, flags, left())) {
|
|
9980
10403
|
const realMask = {};
|
|
9981
10404
|
layer.realMask = realMask;
|
|
9982
10405
|
const realFlags = readUint8(reader);
|
|
@@ -10005,6 +10428,43 @@ function readLayerMaskData(reader, layer) {
|
|
|
10005
10428
|
skipBytes(reader, left());
|
|
10006
10429
|
});
|
|
10007
10430
|
}
|
|
10431
|
+
function maskParamsSize(params) {
|
|
10432
|
+
return 1 +
|
|
10433
|
+
((params & 1 /* MaskParams.UserMaskDensity */) ? 1 : 0) +
|
|
10434
|
+
((params & 2 /* MaskParams.UserMaskFeather */) ? 8 : 0) +
|
|
10435
|
+
((params & 4 /* MaskParams.VectorMaskDensity */) ? 1 : 0) +
|
|
10436
|
+
((params & 8 /* MaskParams.VectorMaskFeather */) ? 8 : 0);
|
|
10437
|
+
}
|
|
10438
|
+
// checks if data at offset is mask parameters followed by up to 3 bytes of zero padding, ending exactly at offset + left
|
|
10439
|
+
function isMaskParamsLayout(view, offset, left) {
|
|
10440
|
+
if (left < 1)
|
|
10441
|
+
return false;
|
|
10442
|
+
const params = view.getUint8(offset);
|
|
10443
|
+
if (params === 0 || (params & ~0x0f))
|
|
10444
|
+
return false; // only 4 parameter flags exist
|
|
10445
|
+
const size = maskParamsSize(params);
|
|
10446
|
+
if (left < size || left - size > 3)
|
|
10447
|
+
return false;
|
|
10448
|
+
for (let i = size; i < left; i++) {
|
|
10449
|
+
if (view.getUint8(offset + i) !== 0)
|
|
10450
|
+
return false;
|
|
10451
|
+
}
|
|
10452
|
+
return true;
|
|
10453
|
+
}
|
|
10454
|
+
// real mask data (18 bytes) is followed by mask parameters (if flag is set) and padding
|
|
10455
|
+
function hasRealMaskData(reader, flags, left) {
|
|
10456
|
+
if (left < 18)
|
|
10457
|
+
return false;
|
|
10458
|
+
if (!(flags & 16 /* LayerMaskFlags.MaskHasParametersAppliedToIt */))
|
|
10459
|
+
return true;
|
|
10460
|
+
const { view, offset } = reader;
|
|
10461
|
+
if (isMaskParamsLayout(view, offset, left))
|
|
10462
|
+
return false;
|
|
10463
|
+
if (isMaskParamsLayout(view, offset + 18, left - 18))
|
|
10464
|
+
return true;
|
|
10465
|
+
// unknown layout, assume real mask if there's enough data for it (and mask parameters)
|
|
10466
|
+
return left === 18 || left - 18 >= maskParamsSize(view.getUint8(offset + 18));
|
|
10467
|
+
}
|
|
10008
10468
|
function readBlendingRange(reader) {
|
|
10009
10469
|
return [readUint8(reader), readUint8(reader), readUint8(reader), readUint8(reader)];
|
|
10010
10470
|
}
|
|
@@ -10071,8 +10531,12 @@ function getCompositeImageData(psd) {
|
|
|
10071
10531
|
if (!data)
|
|
10072
10532
|
return undefined;
|
|
10073
10533
|
const reader = createReader(data.buffer, data.byteOffset, data.byteLength);
|
|
10074
|
-
const
|
|
10075
|
-
|
|
10534
|
+
const info = psd.rawCompositeDataInfo;
|
|
10535
|
+
if (info) {
|
|
10536
|
+
reader.large = info.large;
|
|
10537
|
+
reader.globalAlpha = info.globalAlpha;
|
|
10538
|
+
}
|
|
10539
|
+
return readImageData(reader, psd);
|
|
10076
10540
|
}
|
|
10077
10541
|
function getCompositeCanvas(psd) {
|
|
10078
10542
|
return imageDataToCanvasSafe(getCompositeImageData(psd));
|
|
@@ -10114,18 +10578,18 @@ function decodeLayerPixels(layer, useImageData) {
|
|
|
10114
10578
|
function decodeLayerImageData(layer, options) {
|
|
10115
10579
|
var _a, _b, _c;
|
|
10116
10580
|
let { throwForMissingFeatures, useImageData } = options;
|
|
10117
|
-
const imageData = getDataFromLayer(layer, LayerDataType.Layer, throwForMissingFeatures, options.totalMemoryLimit);
|
|
10581
|
+
const imageData = getDataFromLayer(layer, LayerDataType.Layer, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
10118
10582
|
setImageDataOrCanvas(layer, imageData, useImageData);
|
|
10119
10583
|
if (options.totalMemoryLimit !== undefined)
|
|
10120
10584
|
options.totalMemoryLimit -= (_a = imageData === null || imageData === void 0 ? void 0 : imageData.data.byteLength) !== null && _a !== void 0 ? _a : 0;
|
|
10121
10585
|
if (layer.mask) {
|
|
10122
|
-
const maskData = getDataFromLayer(layer, LayerDataType.Mask, throwForMissingFeatures, options.totalMemoryLimit);
|
|
10586
|
+
const maskData = getDataFromLayer(layer, LayerDataType.Mask, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
10123
10587
|
setImageDataOrCanvas(layer.mask, maskData, useImageData);
|
|
10124
10588
|
if (options.totalMemoryLimit !== undefined)
|
|
10125
10589
|
options.totalMemoryLimit -= (_b = maskData === null || maskData === void 0 ? void 0 : maskData.data.byteLength) !== null && _b !== void 0 ? _b : 0;
|
|
10126
10590
|
}
|
|
10127
10591
|
if (layer.realMask) {
|
|
10128
|
-
const maskData = getDataFromLayer(layer, LayerDataType.RealMask, throwForMissingFeatures, options.totalMemoryLimit);
|
|
10592
|
+
const maskData = getDataFromLayer(layer, LayerDataType.RealMask, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
10129
10593
|
setImageDataOrCanvas(layer.realMask, maskData, useImageData);
|
|
10130
10594
|
if (options.totalMemoryLimit !== undefined)
|
|
10131
10595
|
options.totalMemoryLimit -= (_c = maskData === null || maskData === void 0 ? void 0 : maskData.data.byteLength) !== null && _c !== void 0 ? _c : 0;
|
|
@@ -10138,7 +10602,8 @@ var LayerDataType;
|
|
|
10138
10602
|
LayerDataType[LayerDataType["Mask"] = 1] = "Mask";
|
|
10139
10603
|
LayerDataType[LayerDataType["RealMask"] = 2] = "RealMask";
|
|
10140
10604
|
})(LayerDataType || (LayerDataType = {}));
|
|
10141
|
-
function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
10605
|
+
function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, logOptions) {
|
|
10606
|
+
var _a;
|
|
10142
10607
|
if (!layer.rawData)
|
|
10143
10608
|
return undefined;
|
|
10144
10609
|
const { colorMode, bitsPerChannel, channels, large } = layer.rawData;
|
|
@@ -10151,7 +10616,7 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
10151
10616
|
if (layerWidth && layerHeight && read === LayerDataType.Layer) {
|
|
10152
10617
|
if (cmyk) {
|
|
10153
10618
|
if (bitsPerChannel !== 8)
|
|
10154
|
-
throw new Error('bitsPerChannel
|
|
10619
|
+
throw new Error('bitsPerChannel not supported');
|
|
10155
10620
|
imageData = { width: layerWidth, height: layerHeight, data: new Uint8ClampedArray(layerWidth * layerHeight * 5) };
|
|
10156
10621
|
}
|
|
10157
10622
|
else {
|
|
@@ -10166,6 +10631,11 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
10166
10631
|
if (!data)
|
|
10167
10632
|
continue;
|
|
10168
10633
|
const dataReader = createReader(data.buffer, data.byteOffset, data.byteLength);
|
|
10634
|
+
dataReader.debug = !!(logOptions === null || logOptions === void 0 ? void 0 : logOptions.debug);
|
|
10635
|
+
if (logOptions === null || logOptions === void 0 ? void 0 : logOptions.log)
|
|
10636
|
+
dataReader.log = logOptions.log;
|
|
10637
|
+
if (memoryLimit !== undefined)
|
|
10638
|
+
dataReader.totalMemoryLimit = Math.max(0, memoryLimit - ((_a = imageData === null || imageData === void 0 ? void 0 : imageData.data.byteLength) !== null && _a !== void 0 ? _a : 0));
|
|
10169
10639
|
if (id === -2 /* ChannelID.UserMask */ || id === -3 /* ChannelID.RealUserMask */) {
|
|
10170
10640
|
if (id === -2 /* ChannelID.UserMask */ && read !== LayerDataType.Mask)
|
|
10171
10641
|
continue;
|
|
@@ -10178,6 +10648,8 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
10178
10648
|
const maskHeight = Math.max(0, (mask.bottom || 0) - (mask.top || 0));
|
|
10179
10649
|
if (maskWidth && maskHeight) {
|
|
10180
10650
|
maskData = createImageDataBitDepth(maskWidth, maskHeight, bitsPerChannel, 4, memoryLimit);
|
|
10651
|
+
if (memoryLimit !== undefined)
|
|
10652
|
+
dataReader.totalMemoryLimit = Math.max(0, dataReader.totalMemoryLimit - maskData.data.byteLength);
|
|
10181
10653
|
readData(dataReader, data.byteLength, maskData, compression, maskWidth, maskHeight, bitsPerChannel, 0, large, 4);
|
|
10182
10654
|
if (helpers_1.RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
|
|
10183
10655
|
if (id === -2 /* ChannelID.UserMask */) {
|
|
@@ -10209,15 +10681,14 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
10209
10681
|
layer.imageDataRawCompression[id] = compression;
|
|
10210
10682
|
layer.imageDataRaw[id] = data;
|
|
10211
10683
|
}
|
|
10212
|
-
if (targetData && colorMode === 1 /* ColorMode.Grayscale */) {
|
|
10213
|
-
setupGrayscale(targetData);
|
|
10214
|
-
}
|
|
10215
10684
|
}
|
|
10216
10685
|
if (id === -1 /* ChannelID.Transparency */) {
|
|
10217
10686
|
initializedAlpha = true;
|
|
10218
10687
|
}
|
|
10219
10688
|
}
|
|
10220
10689
|
if (imageData) {
|
|
10690
|
+
if (colorMode === 1 /* ColorMode.Grayscale */)
|
|
10691
|
+
setupGrayscale(imageData);
|
|
10221
10692
|
if (!initializedAlpha)
|
|
10222
10693
|
resetAlpha(imageData, cmyk);
|
|
10223
10694
|
if (cmyk) {
|
|
@@ -10233,7 +10704,7 @@ function readData(reader, length, pixels, compression, width, height, bitDepth,
|
|
|
10233
10704
|
return;
|
|
10234
10705
|
if (compression === 0 /* Compression.RawData */) {
|
|
10235
10706
|
if (length !== (width * height * Math.floor(bitDepth / 8))) {
|
|
10236
|
-
reader
|
|
10707
|
+
warnOrThrow(reader, `Invalid length (${length}, ${width * height * Math.floor(bitDepth / 8)})`);
|
|
10237
10708
|
}
|
|
10238
10709
|
const data = readBytes(reader, length);
|
|
10239
10710
|
readDataRaw(data, pixels, bitDepth, step, offset);
|
|
@@ -10244,11 +10715,11 @@ function readData(reader, length, pixels, compression, width, height, bitDepth,
|
|
|
10244
10715
|
}
|
|
10245
10716
|
else if (compression === 2 /* Compression.ZipWithoutPrediction */) {
|
|
10246
10717
|
const data = readBytes(reader, length);
|
|
10247
|
-
readDataZip(data, pixels, width, height, bitDepth, step, offset, false);
|
|
10718
|
+
readDataZip(data, pixels, width, height, bitDepth, step, offset, false, reader);
|
|
10248
10719
|
}
|
|
10249
10720
|
else if (compression === 3 /* Compression.ZipWithPrediction */) {
|
|
10250
10721
|
const data = readBytes(reader, length);
|
|
10251
|
-
readDataZip(data, pixels, width, height, bitDepth, step, offset, true);
|
|
10722
|
+
readDataZip(data, pixels, width, height, bitDepth, step, offset, true, reader);
|
|
10252
10723
|
}
|
|
10253
10724
|
else {
|
|
10254
10725
|
throw new Error(`Invalid Compression type: ${compression}`);
|
|
@@ -10263,7 +10734,7 @@ function readGlobalLayerMaskInfo(reader) {
|
|
|
10263
10734
|
const colorSpace2 = readUint16(reader);
|
|
10264
10735
|
const colorSpace3 = readUint16(reader);
|
|
10265
10736
|
const colorSpace4 = readUint16(reader);
|
|
10266
|
-
const opacity = readUint16(reader) /
|
|
10737
|
+
const opacity = readUint16(reader) / 100; // 0 - 100
|
|
10267
10738
|
const kind = readUint8(reader);
|
|
10268
10739
|
skipBytes(reader, left()); // 3 bytes of padding ?
|
|
10269
10740
|
return { overlayColorSpace, colorSpace1, colorSpace2, colorSpace3, colorSpace4, opacity, kind };
|
|
@@ -10343,11 +10814,12 @@ function readImageData(reader, psd) {
|
|
|
10343
10814
|
var _a;
|
|
10344
10815
|
const compression = readUint16(reader);
|
|
10345
10816
|
const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
10817
|
+
const { width, height } = psd;
|
|
10346
10818
|
if (exports.supportedColorModes.indexOf(psd.colorMode) === -1)
|
|
10347
10819
|
throw new Error(`Color mode not supported: ${psd.colorMode}`);
|
|
10348
10820
|
if (compression !== 0 /* Compression.RawData */ && compression !== 1 /* Compression.RleCompressed */)
|
|
10349
10821
|
throw new Error(`Compression type not supported: ${compression}`);
|
|
10350
|
-
const imageData = createImageDataBitDepth(
|
|
10822
|
+
const imageData = createImageDataBitDepth(width, height, bitsPerChannel, 4, reader.totalMemoryLimit);
|
|
10351
10823
|
if (reader.totalMemoryLimit !== undefined)
|
|
10352
10824
|
reader.totalMemoryLimit -= imageData.data.byteLength;
|
|
10353
10825
|
(0, helpers_1.resetImageData)(imageData);
|
|
@@ -10355,46 +10827,26 @@ function readImageData(reader, psd) {
|
|
|
10355
10827
|
case 0 /* ColorMode.Bitmap */: {
|
|
10356
10828
|
if (bitsPerChannel !== 1)
|
|
10357
10829
|
throw new Error('Invalid bitsPerChannel for bitmap color mode');
|
|
10830
|
+
const rowBytes = Math.ceil(width / 8);
|
|
10358
10831
|
let bytes;
|
|
10359
10832
|
if (compression === 0 /* Compression.RawData */) {
|
|
10360
|
-
bytes = readBytes(reader,
|
|
10361
|
-
}
|
|
10362
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
10363
|
-
bytes = new Uint8Array(psd.width * psd.height);
|
|
10364
|
-
readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, 8, 1, [0], reader.large);
|
|
10833
|
+
bytes = readBytes(reader, rowBytes * height);
|
|
10365
10834
|
}
|
|
10366
10835
|
else {
|
|
10367
|
-
|
|
10836
|
+
bytes = new Uint8Array(rowBytes * height);
|
|
10837
|
+
readDataRLE(reader, { data: bytes, width: rowBytes, height }, rowBytes, height, 8, 1, [0], reader.large);
|
|
10368
10838
|
}
|
|
10369
|
-
(0, helpers_1.decodeBitmap)(bytes, imageData.data,
|
|
10839
|
+
(0, helpers_1.decodeBitmap)(bytes, imageData.data, width, height);
|
|
10370
10840
|
break;
|
|
10371
10841
|
}
|
|
10372
10842
|
case 3 /* ColorMode.RGB */:
|
|
10373
10843
|
case 1 /* ColorMode.Grayscale */: {
|
|
10374
|
-
const
|
|
10375
|
-
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
}
|
|
10381
|
-
else if (reader.globalAlpha) {
|
|
10382
|
-
channels.push(3);
|
|
10383
|
-
}
|
|
10384
|
-
if (compression === 0 /* Compression.RawData */) {
|
|
10385
|
-
for (let i = 0; i < channels.length; i++) {
|
|
10386
|
-
const data = readBytes(reader, psd.width * psd.height * Math.floor(bitsPerChannel / 8));
|
|
10387
|
-
readDataRaw(data, imageData, bitsPerChannel, 4, channels[i]);
|
|
10388
|
-
}
|
|
10389
|
-
}
|
|
10390
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
10391
|
-
const start = reader.offset;
|
|
10392
|
-
readDataRLE(reader, imageData, psd.width, psd.height, bitsPerChannel, 4, channels, reader.large);
|
|
10393
|
-
if (helpers_1.RAW_IMAGE_DATA)
|
|
10394
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
10395
|
-
}
|
|
10396
|
-
else {
|
|
10397
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
10844
|
+
const colorChannels = psd.colorMode === 1 /* ColorMode.Grayscale */ ? 1 : 3;
|
|
10845
|
+
const offsets = compositeChannelOffsets(reader, psd, colorChannels, 3);
|
|
10846
|
+
const start = reader.offset;
|
|
10847
|
+
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);
|
|
10398
10850
|
}
|
|
10399
10851
|
if (psd.colorMode === 1 /* ColorMode.Grayscale */) {
|
|
10400
10852
|
setupGrayscale(imageData);
|
|
@@ -10403,57 +10855,25 @@ function readImageData(reader, psd) {
|
|
|
10403
10855
|
}
|
|
10404
10856
|
case 2 /* ColorMode.Indexed */: {
|
|
10405
10857
|
if (bitsPerChannel !== 8)
|
|
10406
|
-
throw new Error('bitsPerChannel
|
|
10407
|
-
if (psd.channels !== 1)
|
|
10408
|
-
throw new Error('Invalid channel count');
|
|
10858
|
+
throw new Error('bitsPerChannel not supported');
|
|
10409
10859
|
if (!psd.palette)
|
|
10410
10860
|
throw new Error('Missing color palette');
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
|
|
10415
|
-
const indexedImageData = {
|
|
10416
|
-
width: imageData.width,
|
|
10417
|
-
height: imageData.height,
|
|
10418
|
-
data: new Uint8Array(imageData.width * imageData.height),
|
|
10419
|
-
};
|
|
10420
|
-
readDataRLE(reader, indexedImageData, psd.width, psd.height, bitsPerChannel, 1, [0], reader.large);
|
|
10421
|
-
indexedToRgb(indexedImageData, imageData, psd.palette);
|
|
10422
|
-
}
|
|
10423
|
-
else {
|
|
10424
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
10425
|
-
}
|
|
10861
|
+
const offsets = compositeChannelOffsets(reader, psd, 1, -1);
|
|
10862
|
+
const indexedImageData = { width, height, data: new Uint8Array(width * height) };
|
|
10863
|
+
readCompositeChannels(reader, compression, indexedImageData, 8, 1, offsets);
|
|
10864
|
+
indexedToRgb(indexedImageData, imageData, psd.palette);
|
|
10426
10865
|
break;
|
|
10427
10866
|
}
|
|
10428
10867
|
case 4 /* ColorMode.CMYK */: {
|
|
10429
10868
|
if (bitsPerChannel !== 8)
|
|
10430
|
-
throw new Error('bitsPerChannel
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
const
|
|
10434
|
-
|
|
10435
|
-
|
|
10436
|
-
if (compression ===
|
|
10437
|
-
|
|
10438
|
-
// TODO: ...
|
|
10439
|
-
// for (let i = 0; i < channels.length; i++) {
|
|
10440
|
-
// readDataRaw(reader, imageData, channels[i], psd.width, psd.height);
|
|
10441
|
-
// }
|
|
10442
|
-
}
|
|
10443
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
10444
|
-
const cmykImageData = {
|
|
10445
|
-
width: imageData.width,
|
|
10446
|
-
height: imageData.height,
|
|
10447
|
-
data: new Uint8Array(imageData.width * imageData.height * 5),
|
|
10448
|
-
};
|
|
10449
|
-
const start = reader.offset;
|
|
10450
|
-
readDataRLE(reader, cmykImageData, psd.width, psd.height, bitsPerChannel, 5, channels, reader.large);
|
|
10451
|
-
cmykToRgb(cmykImageData, imageData, true);
|
|
10452
|
-
if (helpers_1.RAW_IMAGE_DATA)
|
|
10453
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
10454
|
-
}
|
|
10455
|
-
else {
|
|
10456
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
10869
|
+
throw new Error('bitsPerChannel not supported');
|
|
10870
|
+
const offsets = compositeChannelOffsets(reader, psd, 4, 4);
|
|
10871
|
+
const cmykImageData = { width, height, data: new Uint8Array(width * height * 5) };
|
|
10872
|
+
const start = reader.offset;
|
|
10873
|
+
readCompositeChannels(reader, compression, cmykImageData, 8, 5, offsets);
|
|
10874
|
+
cmykToRgb(cmykImageData, imageData, true);
|
|
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);
|
|
10457
10877
|
}
|
|
10458
10878
|
break;
|
|
10459
10879
|
}
|
|
@@ -10461,23 +10881,98 @@ function readImageData(reader, psd) {
|
|
|
10461
10881
|
}
|
|
10462
10882
|
// remove weird white matte
|
|
10463
10883
|
if (reader.globalAlpha) {
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10884
|
+
removeWhiteMatte(imageData);
|
|
10885
|
+
}
|
|
10886
|
+
return imageData;
|
|
10887
|
+
}
|
|
10888
|
+
// returns target offset for each of the composite image channels stored in the file, -1 for channels that are skipped
|
|
10889
|
+
function compositeChannelOffsets(reader, psd, colorChannels, alphaOffset) {
|
|
10890
|
+
var _a, _b, _c, _d;
|
|
10891
|
+
const channelCount = (_a = psd.channels) !== null && _a !== void 0 ? _a : (colorChannels + (reader.globalAlpha ? 1 : 0));
|
|
10892
|
+
if (channelCount < colorChannels)
|
|
10893
|
+
throw new Error(`Invalid channel count: ${channelCount}`);
|
|
10894
|
+
// First extra channel is transparency if document has global alpha (negative layer count). Some non-Photoshop
|
|
10895
|
+
// applications write transparency channel without setting global alpha, in that case extra channel is not
|
|
10896
|
+
// listed in alpha channel names (Photoshop names all user alpha channels / saved selections).
|
|
10897
|
+
const namedChannels = (_d = (_c = (_b = psd.imageResources) === null || _b === void 0 ? void 0 : _b.alphaChannelNames) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
10898
|
+
const hasTransparency = reader.globalAlpha || (channelCount - colorChannels) > namedChannels;
|
|
10899
|
+
const offsets = [];
|
|
10900
|
+
for (let i = 0; i < channelCount; i++) {
|
|
10901
|
+
if (i < colorChannels) {
|
|
10902
|
+
offsets.push(i);
|
|
10903
|
+
}
|
|
10904
|
+
else if (i === colorChannels && hasTransparency && alphaOffset >= 0) {
|
|
10905
|
+
offsets.push(alphaOffset);
|
|
10906
|
+
}
|
|
10907
|
+
else {
|
|
10908
|
+
// TODO: store these channels (alpha channels / saved selections, spot colors) in additional image data
|
|
10909
|
+
offsets.push(-1);
|
|
10910
|
+
}
|
|
10911
|
+
}
|
|
10912
|
+
return offsets;
|
|
10913
|
+
}
|
|
10914
|
+
function readCompositeChannels(reader, compression, pixelData, bitsPerChannel, step, offsets) {
|
|
10915
|
+
if (compression === 0 /* Compression.RawData */) {
|
|
10916
|
+
const channelSize = pixelData.width * pixelData.height * bytesPerValue(bitsPerChannel);
|
|
10917
|
+
for (const offset of offsets) {
|
|
10918
|
+
if (offset < 0) {
|
|
10919
|
+
skipBytes(reader, channelSize);
|
|
10920
|
+
}
|
|
10921
|
+
else {
|
|
10922
|
+
readDataRaw(readBytes(reader, channelSize), pixelData, bitsPerChannel, step, offset);
|
|
10923
|
+
}
|
|
10924
|
+
}
|
|
10925
|
+
}
|
|
10926
|
+
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
10927
|
+
readDataRLE(reader, pixelData, pixelData.width, pixelData.height, bitsPerChannel, step, offsets, reader.large);
|
|
10928
|
+
}
|
|
10929
|
+
else {
|
|
10930
|
+
throw new Error(`Compression not supported: ${compression}`);
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10933
|
+
// un-premultiplies colors from white matte, used for composite image of documents with global alpha
|
|
10934
|
+
function removeWhiteMatte({ data, width, height }) {
|
|
10935
|
+
const size = width * height * 4;
|
|
10936
|
+
if (data instanceof Float32Array) {
|
|
10468
10937
|
for (let i = 0; i < size; i += 4) {
|
|
10469
|
-
const
|
|
10938
|
+
const a = data[i + 3];
|
|
10939
|
+
if (a > 0 && a < 1) {
|
|
10940
|
+
const ra = 1 / a;
|
|
10941
|
+
const invA = 1 - ra;
|
|
10942
|
+
for (let j = 0; j < 3; j++) {
|
|
10943
|
+
const v = data[i + j] * ra + invA;
|
|
10944
|
+
data[i + j] = v < 0 ? 0 : v;
|
|
10945
|
+
}
|
|
10946
|
+
}
|
|
10947
|
+
}
|
|
10948
|
+
}
|
|
10949
|
+
else if (data instanceof Uint16Array) {
|
|
10950
|
+
for (let i = 0; i < size; i += 4) {
|
|
10951
|
+
const pa = data[i + 3];
|
|
10952
|
+
if (pa !== 0 && pa !== 0xffff) {
|
|
10953
|
+
const ra = 0xffff / pa;
|
|
10954
|
+
const invA = 0xffff * (1 - ra);
|
|
10955
|
+
for (let j = 0; j < 3; j++) {
|
|
10956
|
+
const v = Math.round(data[i + j] * ra + invA);
|
|
10957
|
+
data[i + j] = v < 0 ? 0 : (v > 0xffff ? 0xffff : v);
|
|
10958
|
+
}
|
|
10959
|
+
}
|
|
10960
|
+
}
|
|
10961
|
+
}
|
|
10962
|
+
else {
|
|
10963
|
+
// Uint8ClampedArray clamps and rounds values on assignment
|
|
10964
|
+
for (let i = 0; i < size; i += 4) {
|
|
10965
|
+
const pa = data[i + 3];
|
|
10470
10966
|
if (pa != 0 && pa != 255) {
|
|
10471
10967
|
const a = pa / 255;
|
|
10472
10968
|
const ra = 1 / a;
|
|
10473
10969
|
const invA = 255 * (1 - ra);
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10970
|
+
data[i + 0] = data[i + 0] * ra + invA;
|
|
10971
|
+
data[i + 1] = data[i + 1] * ra + invA;
|
|
10972
|
+
data[i + 2] = data[i + 2] * ra + invA;
|
|
10477
10973
|
}
|
|
10478
10974
|
}
|
|
10479
10975
|
}
|
|
10480
|
-
return imageData;
|
|
10481
10976
|
}
|
|
10482
10977
|
function cmykToRgb(cmyk, rgb, reverseAlpha) {
|
|
10483
10978
|
const size = rgb.width * rgb.height * 4;
|
|
@@ -10516,175 +11011,267 @@ function indexedToRgb(indexed, rgb, palette) {
|
|
|
10516
11011
|
dstData[dst + 3] = 255;
|
|
10517
11012
|
}
|
|
10518
11013
|
}
|
|
10519
|
-
|
|
10520
|
-
|
|
10521
|
-
|
|
11014
|
+
// number of bytes used to store single channel value, 1-bit data is handled as bytes
|
|
11015
|
+
function bytesPerValue(bitDepth) {
|
|
11016
|
+
switch (bitDepth) {
|
|
11017
|
+
case 1:
|
|
11018
|
+
case 8: return 1;
|
|
11019
|
+
case 16: return 2;
|
|
11020
|
+
case 32: return 4;
|
|
11021
|
+
default: throw new Error(`Invalid bitDepth (${bitDepth})`);
|
|
10522
11022
|
}
|
|
10523
11023
|
}
|
|
10524
|
-
function
|
|
10525
|
-
if (
|
|
10526
|
-
|
|
11024
|
+
function verifyArrayType(data, bytesPerValue) {
|
|
11025
|
+
if (data.BYTES_PER_ELEMENT !== bytesPerValue) {
|
|
11026
|
+
throw new Error('Invalid array types');
|
|
10527
11027
|
}
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
}
|
|
10541
|
-
else {
|
|
10542
|
-
return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
|
|
11028
|
+
}
|
|
11029
|
+
// NOTE: `buffer` may alias input file data, it must not be modified here
|
|
11030
|
+
function readDataRaw(buffer, pixelData, bitDepth, step, offset) {
|
|
11031
|
+
const bpv = bytesPerValue(bitDepth);
|
|
11032
|
+
if (!pixelData || offset < 0 || offset >= step)
|
|
11033
|
+
return;
|
|
11034
|
+
const data = pixelData.data;
|
|
11035
|
+
verifyArrayType(data, bpv);
|
|
11036
|
+
const size = Math.min(pixelData.width * pixelData.height, Math.floor(buffer.byteLength / bpv)) | 0;
|
|
11037
|
+
if (bpv === 1) {
|
|
11038
|
+
for (let i = 0, p = offset | 0; i < size; i++, p = (p + step) | 0) {
|
|
11039
|
+
data[p] = buffer[i];
|
|
10543
11040
|
}
|
|
10544
11041
|
}
|
|
10545
|
-
else if (
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
new Uint8Array(result.buffer, result.byteOffset, result.byteLength).set(bytes);
|
|
10549
|
-
return result;
|
|
10550
|
-
}
|
|
10551
|
-
else {
|
|
10552
|
-
return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
|
|
11042
|
+
else if (bpv === 2) {
|
|
11043
|
+
for (let i = 0, j = 0, p = offset | 0; i < size; i++, j += 2, p = (p + step) | 0) {
|
|
11044
|
+
data[p] = (buffer[j] << 8) | buffer[j + 1];
|
|
10553
11045
|
}
|
|
10554
11046
|
}
|
|
10555
11047
|
else {
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
function copyChannelToPixelData(pixelData, channel, offset, step) {
|
|
10560
|
-
verifyCompatible(pixelData.data, channel);
|
|
10561
|
-
const size = pixelData.width * pixelData.height;
|
|
10562
|
-
const data = pixelData.data;
|
|
10563
|
-
for (let i = 0, p = offset | 0; i < size; i++, p = (p + step) | 0) {
|
|
10564
|
-
data[p] = channel[i];
|
|
10565
|
-
}
|
|
10566
|
-
}
|
|
10567
|
-
function readDataRaw(buffer, pixelData, bitDepth, step, offset) {
|
|
10568
|
-
if (bitDepth == 32) {
|
|
10569
|
-
for (let i = 0; i < buffer.byteLength; i += 4) {
|
|
10570
|
-
const a = buffer[i + 0];
|
|
10571
|
-
const b = buffer[i + 1];
|
|
10572
|
-
const c = buffer[i + 2];
|
|
10573
|
-
const d = buffer[i + 3];
|
|
10574
|
-
buffer[i + 0] = d;
|
|
10575
|
-
buffer[i + 1] = c;
|
|
10576
|
-
buffer[i + 2] = b;
|
|
10577
|
-
buffer[i + 3] = a;
|
|
11048
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
11049
|
+
for (let i = 0, j = 0, p = offset | 0; i < size; i++, j += 4, p = (p + step) | 0) {
|
|
11050
|
+
data[p] = view.getFloat32(j, false);
|
|
10578
11051
|
}
|
|
10579
11052
|
}
|
|
10580
|
-
const array = bytesToArray(buffer, bitDepth);
|
|
10581
|
-
if (pixelData && offset < step) {
|
|
10582
|
-
copyChannelToPixelData(pixelData, array, offset, step);
|
|
10583
|
-
}
|
|
10584
11053
|
}
|
|
10585
|
-
function decodePredicted(data, width, height
|
|
11054
|
+
function decodePredicted(data, width, height) {
|
|
10586
11055
|
for (let y = 0; y < height; y++) {
|
|
10587
11056
|
const offset = y * width;
|
|
10588
11057
|
for (let x = 1, o = offset + 1; x < width; x++, o++) {
|
|
10589
|
-
data[o] =
|
|
11058
|
+
data[o] = data[o - 1] + data[o]; // Uint8Array wraps values on assignment
|
|
11059
|
+
}
|
|
11060
|
+
}
|
|
11061
|
+
}
|
|
11062
|
+
const zipOverflow = new Error('Decompressed data exceeds expected size');
|
|
11063
|
+
// inflates data, stopping when output exceeds expected size (protects against zip bombs)
|
|
11064
|
+
function inflateLimited(compressed, expectedSize, reader) {
|
|
11065
|
+
const output = new Uint8Array(expectedSize);
|
|
11066
|
+
let position = 0;
|
|
11067
|
+
let overflow = false;
|
|
11068
|
+
const inflator = new pako_1.Inflate({ chunkSize: Math.max(1024, Math.min(expectedSize, 0x10000)) });
|
|
11069
|
+
inflator.onData = (chunk) => {
|
|
11070
|
+
const data = chunk;
|
|
11071
|
+
const count = Math.min(data.length, expectedSize - position);
|
|
11072
|
+
if (count > 0)
|
|
11073
|
+
output.set(count === data.length ? data : data.subarray(0, count), position);
|
|
11074
|
+
position += count;
|
|
11075
|
+
if (count < data.length) {
|
|
11076
|
+
overflow = true;
|
|
11077
|
+
throw zipOverflow;
|
|
10590
11078
|
}
|
|
11079
|
+
};
|
|
11080
|
+
inflator.onEnd = (status) => {
|
|
11081
|
+
var _a;
|
|
11082
|
+
// default handler collects all the chunks into result, we only need the error status
|
|
11083
|
+
inflator.err = status;
|
|
11084
|
+
inflator.msg = ((_a = inflator.strm) === null || _a === void 0 ? void 0 : _a.msg) || '';
|
|
11085
|
+
};
|
|
11086
|
+
try {
|
|
11087
|
+
inflator.push(compressed, true);
|
|
11088
|
+
}
|
|
11089
|
+
catch (e) {
|
|
11090
|
+
if (e !== zipOverflow)
|
|
11091
|
+
throw e;
|
|
11092
|
+
}
|
|
11093
|
+
if (overflow) {
|
|
11094
|
+
if (reader)
|
|
11095
|
+
warnOrThrow(reader, zipOverflow.message);
|
|
11096
|
+
}
|
|
11097
|
+
else if (inflator.err) {
|
|
11098
|
+
throw new Error(`Invalid zip data: ${inflator.msg}`);
|
|
10591
11099
|
}
|
|
11100
|
+
return output;
|
|
10592
11101
|
}
|
|
10593
|
-
function readDataZip(compressed, pixelData, width, height, bitDepth, step, offset, prediction) {
|
|
10594
|
-
const
|
|
10595
|
-
if (pixelData
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
11102
|
+
function readDataZip(compressed, pixelData, width, height, bitDepth, step, offset, prediction, reader) {
|
|
11103
|
+
const bpv = bytesPerValue(bitDepth);
|
|
11104
|
+
if (!pixelData || offset < 0 || offset >= step)
|
|
11105
|
+
return;
|
|
11106
|
+
const data = pixelData.data;
|
|
11107
|
+
verifyArrayType(data, bpv);
|
|
11108
|
+
const expectedSize = width * height * bpv;
|
|
11109
|
+
if (reader)
|
|
11110
|
+
consumeMemory(reader, expectedSize);
|
|
11111
|
+
try {
|
|
11112
|
+
const decompressed = inflateLimited(compressed, expectedSize, reader);
|
|
11113
|
+
if (bpv === 1) {
|
|
11114
|
+
for (let y = 0, i = 0; y < height; y++) {
|
|
11115
|
+
let prev = 0;
|
|
11116
|
+
for (let x = 0, p = offset + y * width * step; x < width; x++, i++, p += step) {
|
|
11117
|
+
let v = decompressed[i];
|
|
11118
|
+
if (prediction)
|
|
11119
|
+
v = prev = (prev + v) & 0xff;
|
|
11120
|
+
data[p] = v;
|
|
11121
|
+
}
|
|
11122
|
+
}
|
|
10606
11123
|
}
|
|
10607
|
-
else if (
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
const b = a + width;
|
|
10616
|
-
const c = b + width;
|
|
10617
|
-
const d = c + width;
|
|
10618
|
-
dst[di] = ((decompressed[a] << 24) | (decompressed[b] << 16) | (decompressed[c] << 8) | decompressed[d]) >>> 0;
|
|
11124
|
+
else if (bpv === 2) {
|
|
11125
|
+
for (let y = 0, i = 0; y < height; y++) {
|
|
11126
|
+
let prev = 0;
|
|
11127
|
+
for (let x = 0, p = offset + y * width * step; x < width; x++, i += 2, p += step) {
|
|
11128
|
+
let v = (decompressed[i] << 8) | decompressed[i + 1];
|
|
11129
|
+
if (prediction)
|
|
11130
|
+
v = prev = (prev + v) & 0xffff;
|
|
11131
|
+
data[p] = v;
|
|
10619
11132
|
}
|
|
10620
11133
|
}
|
|
10621
11134
|
}
|
|
10622
11135
|
else {
|
|
10623
|
-
|
|
11136
|
+
const dst = new Uint32Array(data.buffer, data.byteOffset, data.length);
|
|
11137
|
+
if (prediction) {
|
|
11138
|
+
// bytes are delta encoded per row and stored in planar order (all 1st bytes, all 2nd bytes, ...)
|
|
11139
|
+
decodePredicted(decompressed, width * 4, height);
|
|
11140
|
+
for (let y = 0, di = offset; y < height; y++) {
|
|
11141
|
+
let a = width * 4 * y;
|
|
11142
|
+
for (let x = 0; x < width; x++, a++, di += step) {
|
|
11143
|
+
const b = a + width;
|
|
11144
|
+
const c = b + width;
|
|
11145
|
+
const d = c + width;
|
|
11146
|
+
dst[di] = ((decompressed[a] << 24) | (decompressed[b] << 16) | (decompressed[c] << 8) | decompressed[d]) >>> 0;
|
|
11147
|
+
}
|
|
11148
|
+
}
|
|
11149
|
+
}
|
|
11150
|
+
else {
|
|
11151
|
+
const view = new DataView(decompressed.buffer, decompressed.byteOffset, decompressed.byteLength);
|
|
11152
|
+
for (let i = 0, j = 0, di = offset, size = width * height; i < size; i++, j += 4, di += step) {
|
|
11153
|
+
dst[di] = view.getUint32(j, false);
|
|
11154
|
+
}
|
|
11155
|
+
}
|
|
10624
11156
|
}
|
|
10625
11157
|
}
|
|
11158
|
+
finally {
|
|
11159
|
+
if (reader)
|
|
11160
|
+
recoverMemory(reader, expectedSize);
|
|
11161
|
+
}
|
|
10626
11162
|
}
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
let
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
11163
|
+
// decodes single PackBits row, returns number of decoded values
|
|
11164
|
+
function decodeRLERow(src, i, end, dst, p, step, count) {
|
|
11165
|
+
let x = 0;
|
|
11166
|
+
while (i < end && x < count) {
|
|
11167
|
+
const header = src[i++];
|
|
11168
|
+
if (header > 128) {
|
|
11169
|
+
if (i >= end)
|
|
11170
|
+
break;
|
|
11171
|
+
const value = src[i++];
|
|
11172
|
+
let n = 257 - header;
|
|
11173
|
+
if (n > count - x)
|
|
11174
|
+
n = count - x;
|
|
11175
|
+
x += n;
|
|
11176
|
+
for (; n > 0; n--, p += step) {
|
|
11177
|
+
dst[p] = value;
|
|
11178
|
+
}
|
|
11179
|
+
}
|
|
11180
|
+
else if (header < 128) {
|
|
11181
|
+
let n = header + 1;
|
|
11182
|
+
if (n > count - x)
|
|
11183
|
+
n = count - x;
|
|
11184
|
+
if (n > end - i)
|
|
11185
|
+
n = end - i;
|
|
11186
|
+
x += n;
|
|
11187
|
+
for (; n > 0; n--, p += step) {
|
|
11188
|
+
dst[p] = src[i++];
|
|
10636
11189
|
}
|
|
10637
11190
|
}
|
|
11191
|
+
else {
|
|
11192
|
+
// ignore 128
|
|
11193
|
+
}
|
|
11194
|
+
}
|
|
11195
|
+
return x;
|
|
11196
|
+
}
|
|
11197
|
+
// converts big-endian 16/32-bit values from bytes and writes them to `data` starting at `p` with `step`
|
|
11198
|
+
function scatterValues(bytes, count, bpv, data, p, step) {
|
|
11199
|
+
if (bpv === 2) {
|
|
11200
|
+
for (let x = 0, i = 0; x < count; x++, i += 2, p += step) {
|
|
11201
|
+
data[p] = (bytes[i] << 8) | bytes[i + 1];
|
|
11202
|
+
}
|
|
10638
11203
|
}
|
|
10639
11204
|
else {
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
for (let y = 0; y < height; y++, li++) {
|
|
10644
|
-
lengths[li] = readUint16(reader);
|
|
10645
|
-
}
|
|
11205
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
11206
|
+
for (let x = 0, i = 0; x < count; x++, i += 4, p += step) {
|
|
11207
|
+
data[p] = view.getFloat32(i, false);
|
|
10646
11208
|
}
|
|
10647
11209
|
}
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
11210
|
+
}
|
|
11211
|
+
// decodes RLE rows of single channel, each row starts at the beginning of the image row
|
|
11212
|
+
function decodeRLEChannel(src, lengths, li, pos, width, height, data, offset, step, bpv, row) {
|
|
11213
|
+
const srcEnd = src.length;
|
|
11214
|
+
const rowSize = width * bpv;
|
|
11215
|
+
for (let y = 0; y < height; y++, li++) {
|
|
11216
|
+
const rowStart = pos < srcEnd ? pos : srcEnd;
|
|
11217
|
+
pos += lengths[li];
|
|
11218
|
+
const rowEnd = pos < srcEnd ? pos : srcEnd;
|
|
11219
|
+
if (rowStart >= rowEnd)
|
|
11220
|
+
continue;
|
|
11221
|
+
if (bpv === 1) {
|
|
11222
|
+
decodeRLERow(src, rowStart, rowEnd, data, offset + y * width * step, step, width);
|
|
10657
11223
|
}
|
|
10658
11224
|
else {
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
11225
|
+
const decoded = decodeRLERow(src, rowStart, rowEnd, row, 0, 1, rowSize);
|
|
11226
|
+
scatterValues(row, Math.floor(decoded / bpv), bpv, data, offset + y * width * step, step);
|
|
11227
|
+
}
|
|
11228
|
+
}
|
|
11229
|
+
}
|
|
11230
|
+
function readDataRLE(reader, pixelData, width, height, bitDepth, step, offsets, large) {
|
|
11231
|
+
const data = pixelData && pixelData.data;
|
|
11232
|
+
const rows = offsets.length * height;
|
|
11233
|
+
const lengthSize = large ? 4 : 2;
|
|
11234
|
+
consumeMemory(reader, rows * lengthSize);
|
|
11235
|
+
try {
|
|
11236
|
+
if ((reader.offset + rows * lengthSize) > reader.view.byteLength) {
|
|
11237
|
+
throw new Error('RLE row lengths exceed buffer length');
|
|
11238
|
+
}
|
|
11239
|
+
const lengths = large ? new Uint32Array(rows) : new Uint16Array(rows);
|
|
11240
|
+
let total = 0;
|
|
11241
|
+
if (large) {
|
|
11242
|
+
for (let i = 0; i < rows; i++)
|
|
11243
|
+
total += (lengths[i] = readUint32(reader));
|
|
11244
|
+
}
|
|
11245
|
+
else {
|
|
11246
|
+
for (let i = 0; i < rows; i++)
|
|
11247
|
+
total += (lengths[i] = readUint16(reader));
|
|
11248
|
+
}
|
|
11249
|
+
const start = reader.offset;
|
|
11250
|
+
const srcEnd = reader.view.byteLength;
|
|
11251
|
+
if (total > (srcEnd - start)) {
|
|
11252
|
+
// broken or truncated file, decode only data that is available
|
|
11253
|
+
warnOrThrow(reader, 'RLE data exceeds buffer length');
|
|
11254
|
+
}
|
|
11255
|
+
const bpv = bytesPerValue(bitDepth);
|
|
11256
|
+
if (data)
|
|
11257
|
+
verifyArrayType(data, bpv);
|
|
11258
|
+
const src = new Uint8Array(reader.view.buffer, reader.view.byteOffset, srcEnd);
|
|
11259
|
+
const row = (data && bpv > 1) ? new Uint8Array(width * bpv) : undefined;
|
|
11260
|
+
let pos = start;
|
|
11261
|
+
for (let c = 0, li = 0; c < offsets.length; c++, li += height) {
|
|
11262
|
+
const offset = offsets[c] | 0;
|
|
11263
|
+
const channelStart = pos;
|
|
11264
|
+
for (let y = 0; y < height; y++)
|
|
11265
|
+
pos += lengths[li + y];
|
|
11266
|
+
if (data && offset >= 0 && offset < step) {
|
|
11267
|
+
decodeRLEChannel(src, lengths, li, channelStart, width, height, data, offset, step, bpv, row);
|
|
10684
11268
|
}
|
|
10685
11269
|
}
|
|
11270
|
+
reader.offset = pos;
|
|
11271
|
+
}
|
|
11272
|
+
finally {
|
|
11273
|
+
recoverMemory(reader, rows * lengthSize);
|
|
10686
11274
|
}
|
|
10687
|
-
recoverMemory(reader, lengths.byteLength);
|
|
10688
11275
|
}
|
|
10689
11276
|
function readSection(reader, round, func, skipEmpty = true, eightBytes = false) {
|
|
10690
11277
|
let length = readUint32(reader);
|
|
@@ -10743,8 +11330,8 @@ function readColor(reader) {
|
|
|
10743
11330
|
const l = readInt16(reader) / 10000;
|
|
10744
11331
|
const ta = readInt16(reader);
|
|
10745
11332
|
const tb = readInt16(reader);
|
|
10746
|
-
const a =
|
|
10747
|
-
const b =
|
|
11333
|
+
const a = (0, helpers_1.normalizeLabAB)(ta, 100);
|
|
11334
|
+
const b = (0, helpers_1.normalizeLabAB)(tb, 100);
|
|
10748
11335
|
skipBytes(reader, 2);
|
|
10749
11336
|
return { l, a, b };
|
|
10750
11337
|
}
|
|
@@ -10944,6 +11531,8 @@ exports.writeUnicodeStringWithoutLength = writeUnicodeStringWithoutLength;
|
|
|
10944
11531
|
exports.writeUnicodeStringWithoutLengthLE = writeUnicodeStringWithoutLengthLE;
|
|
10945
11532
|
exports.writeUnicodeString = writeUnicodeString;
|
|
10946
11533
|
exports.writeUnicodeStringWithPadding = writeUnicodeStringWithPadding;
|
|
11534
|
+
exports.getRLEChannelBound = getRLEChannelBound;
|
|
11535
|
+
exports.writeUint64 = writeUint64;
|
|
10947
11536
|
exports.writeSection = writeSection;
|
|
10948
11537
|
exports.writePsd = writePsd;
|
|
10949
11538
|
exports.writeColor = writeColor;
|
|
@@ -11067,59 +11656,71 @@ function writeUnicodeStringWithPadding(writer, text) {
|
|
|
11067
11656
|
}
|
|
11068
11657
|
writeUint16(writer, 0);
|
|
11069
11658
|
}
|
|
11070
|
-
|
|
11659
|
+
// Worst-case size of writeDataRLE output for a single channel: per row the byte count (2 bytes, 4 for PSB)
|
|
11660
|
+
// plus PackBits data, which in the worst case is all literal runs of up to 128 bytes, each with 1 header byte.
|
|
11661
|
+
function getRLEChannelBound(width, height, large) {
|
|
11662
|
+
return height * ((large ? 4 : 2) + width + Math.ceil(width / 128));
|
|
11663
|
+
}
|
|
11664
|
+
function getLargestLayerSize(layers = [], large) {
|
|
11071
11665
|
let max = 0;
|
|
11072
11666
|
for (const layer of layers) {
|
|
11073
|
-
const
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
}
|
|
11079
|
-
if (layer.realMask) {
|
|
11080
|
-
const { width, height } = getLayerDimentions(layer.realMask);
|
|
11081
|
-
max = Math.max(max, 2 * height + 2 * width * height);
|
|
11667
|
+
for (const target of [layer, layer.mask, layer.realMask]) {
|
|
11668
|
+
if (target) {
|
|
11669
|
+
const { width, height } = getLayerDimentions(target);
|
|
11670
|
+
max = Math.max(max, getRLEChannelBound(width, height, large));
|
|
11671
|
+
}
|
|
11082
11672
|
}
|
|
11083
11673
|
if (layer.children) {
|
|
11084
|
-
max = Math.max(max, getLargestLayerSize(layer.children));
|
|
11674
|
+
max = Math.max(max, getLargestLayerSize(layer.children, large));
|
|
11085
11675
|
}
|
|
11086
11676
|
}
|
|
11087
11677
|
return max;
|
|
11088
11678
|
}
|
|
11679
|
+
function writeUint64(writer, value) {
|
|
11680
|
+
writeUint32(writer, Math.floor(value / 0x100000000));
|
|
11681
|
+
writeUint32(writer, value >>> 0);
|
|
11682
|
+
}
|
|
11089
11683
|
function writeSection(writer, round, func, writeTotalLength = false, large = false) {
|
|
11684
|
+
const offset = writer.offset;
|
|
11090
11685
|
if (large)
|
|
11091
11686
|
writeUint32(writer, 0);
|
|
11092
|
-
const offset = writer.offset;
|
|
11093
11687
|
writeUint32(writer, 0);
|
|
11688
|
+
const start = writer.offset;
|
|
11094
11689
|
func();
|
|
11095
|
-
let length = writer.offset -
|
|
11690
|
+
let length = writer.offset - start;
|
|
11096
11691
|
let len = length;
|
|
11097
11692
|
while (len % round) {
|
|
11098
11693
|
writeUint8(writer, 0);
|
|
11099
11694
|
len++;
|
|
11100
11695
|
}
|
|
11101
|
-
// while (writer.offset % round) {
|
|
11102
|
-
// writeUint8(writer, 0);
|
|
11103
|
-
// len++;
|
|
11104
|
-
// }
|
|
11105
11696
|
if (writeTotalLength) {
|
|
11106
11697
|
length = len;
|
|
11107
11698
|
}
|
|
11108
|
-
|
|
11699
|
+
if (large) {
|
|
11700
|
+
writer.view.setUint32(offset, Math.floor(length / 0x100000000), false);
|
|
11701
|
+
writer.view.setUint32(offset + 4, length >>> 0, false);
|
|
11702
|
+
}
|
|
11703
|
+
else {
|
|
11704
|
+
if (length > 0xffffffff)
|
|
11705
|
+
throw new Error('Section too large, use PSB format instead');
|
|
11706
|
+
writer.view.setUint32(offset, length, false);
|
|
11707
|
+
}
|
|
11708
|
+
}
|
|
11709
|
+
function verifyPixelData(data, name) {
|
|
11710
|
+
// check element size instead of instanceof, so arrays from other realms (iframes, workers, vm) are accepted
|
|
11711
|
+
const bytesPerElement = data && data.data.BYTES_PER_ELEMENT;
|
|
11712
|
+
if (bytesPerElement !== undefined && bytesPerElement !== 1) {
|
|
11713
|
+
throw new Error(`${name} has incorrect bitDepth (only 8-bit Uint8Array or Uint8ClampedArray data is supported for writing)`);
|
|
11714
|
+
}
|
|
11109
11715
|
}
|
|
11110
11716
|
function verifyBitCount(target) {
|
|
11111
|
-
var _a;
|
|
11717
|
+
var _a, _b, _c;
|
|
11112
11718
|
(_a = target.children) === null || _a === void 0 ? void 0 : _a.forEach(verifyBitCount);
|
|
11113
|
-
|
|
11114
|
-
if (
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
const data = target.mask.imageData;
|
|
11119
|
-
if (data && (data.data instanceof Uint32Array || data.data instanceof Uint16Array)) {
|
|
11120
|
-
throw new Error('mask imageData has incorrect bitDepth');
|
|
11121
|
-
}
|
|
11122
|
-
}
|
|
11719
|
+
verifyPixelData(target.imageData, 'imageData');
|
|
11720
|
+
if ('mask' in target)
|
|
11721
|
+
verifyPixelData((_b = target.mask) === null || _b === void 0 ? void 0 : _b.imageData, 'mask imageData');
|
|
11722
|
+
if ('realMask' in target)
|
|
11723
|
+
verifyPixelData((_c = target.realMask) === null || _c === void 0 ? void 0 : _c.imageData, 'realMask imageData');
|
|
11123
11724
|
}
|
|
11124
11725
|
function writePsd(writer, psd, options = {}) {
|
|
11125
11726
|
var _a;
|
|
@@ -11130,6 +11731,10 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11130
11731
|
const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
11131
11732
|
if (bitsPerChannel !== 8)
|
|
11132
11733
|
throw new Error('bitsPerChannel other than 8 are not supported for writing');
|
|
11734
|
+
const layers = [];
|
|
11735
|
+
addChildren(layers, psd.children);
|
|
11736
|
+
if (!layers.length)
|
|
11737
|
+
layers.push({});
|
|
11133
11738
|
verifyBitCount(psd);
|
|
11134
11739
|
const imageResources = Object.assign({}, psd.imageResources);
|
|
11135
11740
|
const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map() });
|
|
@@ -11143,8 +11748,8 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11143
11748
|
if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
|
|
11144
11749
|
throw new Error('Document canvas must have the same size as document');
|
|
11145
11750
|
const globalAlpha = !!imageData && (0, helpers_1.hasAlpha)(imageData);
|
|
11146
|
-
|
|
11147
|
-
writer.tempBuffer = new Uint8Array(
|
|
11751
|
+
// only used for encoding a single layer channel at a time, composite image is encoded directly into the writer buffer
|
|
11752
|
+
writer.tempBuffer = new Uint8Array(getLargestLayerSize(psd.children, !!options.psb));
|
|
11148
11753
|
// header
|
|
11149
11754
|
writeSignature(writer, '8BPS');
|
|
11150
11755
|
writeUint16(writer, options.psb ? 2 : 1); // version
|
|
@@ -11167,10 +11772,6 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11167
11772
|
}
|
|
11168
11773
|
// TODO: other data?
|
|
11169
11774
|
});
|
|
11170
|
-
const layers = [];
|
|
11171
|
-
addChildren(layers, psd.children);
|
|
11172
|
-
if (!layers.length)
|
|
11173
|
-
layers.push({});
|
|
11174
11775
|
// image resources
|
|
11175
11776
|
imageResources.layersGroup = layers.map(l => l.linkGroup || 0);
|
|
11176
11777
|
imageResources.layerGroupsEnabledId = layers.map(l => l.linkGroupEnabled == false ? 0 : 1);
|
|
@@ -11192,36 +11793,45 @@ function writePsd(writer, psd, options = {}) {
|
|
|
11192
11793
|
writeGlobalLayerMaskInfo(writer, psd.globalLayerMaskInfo);
|
|
11193
11794
|
writeAdditionalLayerInfo(writer, psd, psd, opt);
|
|
11194
11795
|
}, undefined, !!opt.psb);
|
|
11796
|
+
writer.tempBuffer = undefined;
|
|
11195
11797
|
// image data
|
|
11196
|
-
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
11197
|
-
const width = imageData ? imageData.width : psd.width;
|
|
11198
|
-
const height = imageData ? imageData.height : psd.height;
|
|
11199
|
-
const data = { data: new Uint8Array(width * height * 4), width, height };
|
|
11200
11798
|
writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
|
|
11201
11799
|
if (helpers_1.RAW_IMAGE_DATA && psd.imageDataRaw) {
|
|
11202
11800
|
console.log('writing raw image data');
|
|
11203
11801
|
writeBytes(writer, psd.imageDataRaw);
|
|
11204
11802
|
}
|
|
11205
11803
|
else {
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
//
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11804
|
+
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
11805
|
+
const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
|
|
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
|
+
}
|
|
11812
|
+
}
|
|
11813
|
+
function getCompositeData(imageData, width, height, globalAlpha) {
|
|
11814
|
+
if (!imageData)
|
|
11815
|
+
return { data: new Uint8Array(width * height * 4), width, height };
|
|
11816
|
+
const size = width * height * 4;
|
|
11817
|
+
const src = imageData.data;
|
|
11818
|
+
let dst = undefined;
|
|
11819
|
+
// add weird white matte (copy the data only if there are semi-transparent pixels)
|
|
11820
|
+
if (globalAlpha) {
|
|
11821
|
+
for (let i = 0; i < size; i += 4) {
|
|
11822
|
+
const pa = src[i + 3];
|
|
11823
|
+
if (pa != 0 && pa != 255) {
|
|
11824
|
+
if (!dst)
|
|
11825
|
+
dst = new Uint8Array(src.buffer, src.byteOffset, size).slice();
|
|
11826
|
+
const a = pa / 255;
|
|
11827
|
+
const ra = 255 * (1 - a);
|
|
11828
|
+
dst[i + 0] = src[i + 0] * a + ra;
|
|
11829
|
+
dst[i + 1] = src[i + 1] * a + ra;
|
|
11830
|
+
dst[i + 2] = src[i + 2] * a + ra;
|
|
11221
11831
|
}
|
|
11222
11832
|
}
|
|
11223
|
-
writeBytes(writer, (0, helpers_1.writeDataRLE)(writer.tempBuffer, data, channels, !!options.psb));
|
|
11224
11833
|
}
|
|
11834
|
+
return dst ? { data: dst, width, height } : imageData;
|
|
11225
11835
|
}
|
|
11226
11836
|
function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
11227
11837
|
writeSection(writer, 4, () => {
|
|
@@ -11238,9 +11848,12 @@ function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
|
11238
11848
|
writeUint16(writer, channels.length);
|
|
11239
11849
|
for (const c of channels) {
|
|
11240
11850
|
writeInt16(writer, c.id);
|
|
11241
|
-
if (options.psb)
|
|
11242
|
-
|
|
11243
|
-
|
|
11851
|
+
if (options.psb) {
|
|
11852
|
+
writeUint64(writer, c.length);
|
|
11853
|
+
}
|
|
11854
|
+
else {
|
|
11855
|
+
writeUint32(writer, c.length);
|
|
11856
|
+
}
|
|
11244
11857
|
}
|
|
11245
11858
|
writeSignature(writer, '8BIM');
|
|
11246
11859
|
writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
|
|
@@ -11277,7 +11890,7 @@ function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
|
11277
11890
|
}, true, options.psb);
|
|
11278
11891
|
}
|
|
11279
11892
|
function writeLayerMaskData(writer, { mask, realMask }, layerData) {
|
|
11280
|
-
writeSection(writer,
|
|
11893
|
+
writeSection(writer, 4, () => {
|
|
11281
11894
|
if (!mask && !realMask)
|
|
11282
11895
|
return;
|
|
11283
11896
|
let params = 0, flags = 0, realFlags = 0;
|
|
@@ -11332,8 +11945,7 @@ function writeLayerMaskData(writer, { mask, realMask }, layerData) {
|
|
|
11332
11945
|
if (mask.vectorMaskFeather !== undefined)
|
|
11333
11946
|
writeFloat64(writer, mask.vectorMaskFeather);
|
|
11334
11947
|
}
|
|
11335
|
-
|
|
11336
|
-
});
|
|
11948
|
+
}, true); // photoshop pads mask data to multiple of 4 bytes and includes padding in the length
|
|
11337
11949
|
}
|
|
11338
11950
|
function writerBlendingRange(writer, range) {
|
|
11339
11951
|
writeUint8(writer, range[0]);
|
|
@@ -11362,7 +11974,7 @@ function writeGlobalLayerMaskInfo(writer, info) {
|
|
|
11362
11974
|
writeUint16(writer, info.colorSpace2);
|
|
11363
11975
|
writeUint16(writer, info.colorSpace3);
|
|
11364
11976
|
writeUint16(writer, info.colorSpace4);
|
|
11365
|
-
writeUint16(writer, Math.round(info.opacity *
|
|
11977
|
+
writeUint16(writer, Math.round((0, helpers_1.clamp)(info.opacity, 0, 1) * 100)); // 0-100
|
|
11366
11978
|
writeUint8(writer, info.kind);
|
|
11367
11979
|
writeZeros(writer, 3);
|
|
11368
11980
|
}
|
|
@@ -11430,10 +12042,8 @@ function addChildren(layers, children) {
|
|
|
11430
12042
|
}
|
|
11431
12043
|
}
|
|
11432
12044
|
function resizeBuffer(writer, size) {
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
newLength *= 2;
|
|
11436
|
-
} while (size > newLength);
|
|
12045
|
+
// grow at least 2x to keep small writes fast, but don't overshoot large reservations (like composite image data)
|
|
12046
|
+
const newLength = Math.max(writer.buffer.byteLength * 2, size);
|
|
11437
12047
|
const newBuffer = new ArrayBuffer(newLength);
|
|
11438
12048
|
const newBytes = new Uint8Array(newBuffer);
|
|
11439
12049
|
const oldBytes = new Uint8Array(writer.buffer);
|
|
@@ -11456,12 +12066,12 @@ function createThumbnail(psd) {
|
|
|
11456
12066
|
let scale = 1;
|
|
11457
12067
|
if (psd.width > psd.height) {
|
|
11458
12068
|
canvas.width = 160;
|
|
11459
|
-
canvas.height = Math.floor(psd.height * (canvas.width / psd.width));
|
|
12069
|
+
canvas.height = Math.max(1, Math.floor(psd.height * (canvas.width / psd.width)));
|
|
11460
12070
|
scale = canvas.width / psd.width;
|
|
11461
12071
|
}
|
|
11462
12072
|
else {
|
|
11463
12073
|
canvas.height = 160;
|
|
11464
|
-
canvas.width = Math.floor(psd.width * (canvas.height / psd.height));
|
|
12074
|
+
canvas.width = Math.max(1, Math.floor(psd.width * (canvas.height / psd.height)));
|
|
11465
12075
|
scale = canvas.height / psd.height;
|
|
11466
12076
|
}
|
|
11467
12077
|
const context = canvas.getContext('2d');
|
|
@@ -11504,7 +12114,7 @@ function getMaskChannels(tempBuffer, layerData, layer, mask, options, realMask)
|
|
|
11504
12114
|
compression = 2 /* Compression.ZipWithoutPrediction */;
|
|
11505
12115
|
}
|
|
11506
12116
|
else {
|
|
11507
|
-
buffer = (0, helpers_1.writeDataRLE)(tempBuffer, imageData, [0], !!options.psb);
|
|
12117
|
+
buffer = (0, helpers_1.writeDataRLE)(tempBuffer, imageData, [0], !!options.psb).slice(); // copy, temp buffer is reused
|
|
11508
12118
|
compression = 1 /* Compression.RleCompressed */;
|
|
11509
12119
|
}
|
|
11510
12120
|
layerData.channels.push({ id: realMask ? -3 /* ChannelID.RealUserMask */ : -2 /* ChannelID.UserMask */, compression, data: buffer, length: 2 + buffer.length });
|
|
@@ -11612,7 +12222,7 @@ function getLayerChannels(tempBuffer, layer, background, options) {
|
|
|
11612
12222
|
compression = 2 /* Compression.ZipWithoutPrediction */;
|
|
11613
12223
|
}
|
|
11614
12224
|
else {
|
|
11615
|
-
data = (0, helpers_1.writeDataRLE)(tempBuffer, imageData, [offset], !!options.psb);
|
|
12225
|
+
data = (0, helpers_1.writeDataRLE)(tempBuffer, imageData, [offset], !!options.psb).slice(); // copy, temp buffer is reused
|
|
11616
12226
|
compression = 1 /* Compression.RleCompressed */;
|
|
11617
12227
|
}
|
|
11618
12228
|
return { id, compression, data, length: 2 + data.length };
|
|
@@ -11676,8 +12286,8 @@ function writeColor(writer, color) {
|
|
|
11676
12286
|
else if ('l' in color) {
|
|
11677
12287
|
writeUint16(writer, 7 /* ColorSpace.Lab */);
|
|
11678
12288
|
writeInt16(writer, Math.round(color.l * 10000));
|
|
11679
|
-
writeInt16(writer, Math.round(
|
|
11680
|
-
writeInt16(writer, Math.round(
|
|
12289
|
+
writeInt16(writer, Math.round((0, helpers_1.denormalizeLabAB)(color.a, 100)));
|
|
12290
|
+
writeInt16(writer, Math.round((0, helpers_1.denormalizeLabAB)(color.b, 100)));
|
|
11681
12291
|
writeUint16(writer, 0);
|
|
11682
12292
|
}
|
|
11683
12293
|
else if ('h' in color) {
|
|
@@ -11727,6 +12337,9 @@ function writePattern(writer, pattern) {
|
|
|
11727
12337
|
writeUint32(writer, bottom);
|
|
11728
12338
|
writeUint32(writer, right);
|
|
11729
12339
|
writeUint32(writer, 24); // channels count
|
|
12340
|
+
// ponytail: pattern channels always use small (2-byte) RLE scanline headers, matching
|
|
12341
|
+
// readPattern which reads them as non-large
|
|
12342
|
+
const buffer = new Uint8Array(getRLEChannelBound(width, height, false));
|
|
11730
12343
|
// channels: RGB at indices 0,1,2 and alpha at index 25
|
|
11731
12344
|
for (let i = 0; i < 24 + 2; i++) {
|
|
11732
12345
|
const offset = i < 3 ? i : (i === 25 ? 3 : -1);
|
|
@@ -11734,10 +12347,6 @@ function writePattern(writer, pattern) {
|
|
|
11734
12347
|
writeUint32(writer, 0); // has
|
|
11735
12348
|
continue;
|
|
11736
12349
|
}
|
|
11737
|
-
// worst-case RLE size for a single channel: width + 1 per scanline, plus scanline length headers
|
|
11738
|
-
const buffer = new Uint8Array(width * height + 2 * height + 2 * width + 16);
|
|
11739
|
-
// ponytail: pattern channels always use small (2-byte) RLE scanline headers, matching
|
|
11740
|
-
// readPattern which reads them as non-large; `large` here only affects the header width.
|
|
11741
12350
|
const data = (0, helpers_1.writeDataRLE)(buffer, pixelData, [offset], false);
|
|
11742
12351
|
writeUint32(writer, 1); // has
|
|
11743
12352
|
writeUint32(writer, data.length + 4 + 16 + 2 + 1); // length
|
|
@@ -11765,6 +12374,7 @@ function writePattern(writer, pattern) {
|
|
|
11765
12374
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11766
12375
|
exports.decodeEngineData = decodeEngineData;
|
|
11767
12376
|
exports.encodeEngineData = encodeEngineData;
|
|
12377
|
+
const helpers_1 = require("./helpers");
|
|
11768
12378
|
const defaultFont = {
|
|
11769
12379
|
name: 'MyriadPro-Regular',
|
|
11770
12380
|
script: 0,
|
|
@@ -11877,6 +12487,26 @@ function decodeColor(color) {
|
|
|
11877
12487
|
default: throw new Error('Unknown color type in text layer');
|
|
11878
12488
|
}
|
|
11879
12489
|
}
|
|
12490
|
+
// h, s, b in 0..1 range, returns r, g, b in 0..1 range
|
|
12491
|
+
function hsbToRgb(h, s, v) {
|
|
12492
|
+
h = (0, helpers_1.clamp)(h || 0, 0, 1);
|
|
12493
|
+
s = (0, helpers_1.clamp)(s || 0, 0, 1);
|
|
12494
|
+
v = (0, helpers_1.clamp)(v || 0, 0, 1);
|
|
12495
|
+
const h6 = (h * 6) % 6;
|
|
12496
|
+
const i = Math.floor(h6);
|
|
12497
|
+
const f = h6 - i;
|
|
12498
|
+
const p = v * (1 - s);
|
|
12499
|
+
const q = v * (1 - s * f);
|
|
12500
|
+
const t = v * (1 - s * (1 - f));
|
|
12501
|
+
switch (i) {
|
|
12502
|
+
case 0: return [v, t, p];
|
|
12503
|
+
case 1: return [q, v, p];
|
|
12504
|
+
case 2: return [p, v, t];
|
|
12505
|
+
case 3: return [p, q, v];
|
|
12506
|
+
case 4: return [t, p, v];
|
|
12507
|
+
default: return [v, p, q];
|
|
12508
|
+
}
|
|
12509
|
+
}
|
|
11880
12510
|
function encodeColor(color) {
|
|
11881
12511
|
if (!color) {
|
|
11882
12512
|
return { Type: 1, Values: [0, 0, 0, 0] };
|
|
@@ -11884,9 +12514,19 @@ function encodeColor(color) {
|
|
|
11884
12514
|
else if ('r' in color) {
|
|
11885
12515
|
return { Type: 1, Values: ['a' in color ? color.a / 255 : 1, color.r / 255, color.g / 255, color.b / 255] };
|
|
11886
12516
|
}
|
|
12517
|
+
else if ('fr' in color) {
|
|
12518
|
+
return { Type: 1, Values: [1, (0, helpers_1.clamp)(color.fr || 0, 0, 1), (0, helpers_1.clamp)(color.fg || 0, 0, 1), (0, helpers_1.clamp)(color.fb || 0, 0, 1)] };
|
|
12519
|
+
}
|
|
12520
|
+
else if ('h' in color) {
|
|
12521
|
+
const [r, g, b] = hsbToRgb(color.h, color.s, color.b);
|
|
12522
|
+
return { Type: 1, Values: [1, r, g, b] };
|
|
12523
|
+
}
|
|
11887
12524
|
else if ('c' in color) {
|
|
11888
12525
|
return { Type: 2, Values: [1, color.c / 255, color.m / 255, color.y / 255, color.k / 255] };
|
|
11889
12526
|
}
|
|
12527
|
+
else if ('l' in color) {
|
|
12528
|
+
throw new Error('LAB colors are not supported in text layers, use RGB, CMYK or grayscale color instead');
|
|
12529
|
+
}
|
|
11890
12530
|
else if ('k' in color) {
|
|
11891
12531
|
return { Type: 0, Values: [1, color.k / 255] };
|
|
11892
12532
|
}
|
|
@@ -11924,16 +12564,19 @@ function findOrAddFont(fonts, font) {
|
|
|
11924
12564
|
return fonts.length - 1;
|
|
11925
12565
|
}
|
|
11926
12566
|
function decodeObject(obj, keys, fonts) {
|
|
12567
|
+
var _a;
|
|
11927
12568
|
const result = {};
|
|
11928
12569
|
for (const key of keys) {
|
|
11929
12570
|
const Key = upperFirst(key);
|
|
11930
12571
|
if (obj[Key] === undefined)
|
|
11931
12572
|
continue;
|
|
11932
12573
|
if (key === 'justification') {
|
|
11933
|
-
result[key] = justification[obj[Key]];
|
|
12574
|
+
result[key] = (_a = justification[obj[Key]]) !== null && _a !== void 0 ? _a : 'left';
|
|
11934
12575
|
}
|
|
11935
12576
|
else if (key === 'font') {
|
|
11936
|
-
|
|
12577
|
+
const font = fonts[obj[Key]];
|
|
12578
|
+
if (font)
|
|
12579
|
+
result[key] = font; // invalid font index, leave the font unset so it falls back to default
|
|
11937
12580
|
}
|
|
11938
12581
|
else if (key === 'fillColor' || key === 'strokeColor') {
|
|
11939
12582
|
result[key] = decodeColor(obj[Key]);
|
|
@@ -11952,7 +12595,7 @@ function encodeObject(obj, keys, fonts) {
|
|
|
11952
12595
|
if (obj[key] === undefined)
|
|
11953
12596
|
continue;
|
|
11954
12597
|
if (key === 'justification') {
|
|
11955
|
-
result[Key] = justification.indexOf((_a = obj[key]) !== null && _a !== void 0 ? _a : 'left');
|
|
12598
|
+
result[Key] = Math.max(0, justification.indexOf((_a = obj[key]) !== null && _a !== void 0 ? _a : 'left')); // default to 'left' for unknown values
|
|
11956
12599
|
}
|
|
11957
12600
|
else if (key === 'font') {
|
|
11958
12601
|
result[Key] = findOrAddFont(fonts, obj[key]);
|
|
@@ -12020,8 +12663,38 @@ function deduplicateValues(base, runs, keys) {
|
|
|
12020
12663
|
runs.length = 0;
|
|
12021
12664
|
}
|
|
12022
12665
|
}
|
|
12666
|
+
function isDefaultGridColor(color) {
|
|
12667
|
+
// Photoshop writes default grid colors as blue with 0 alpha, ignore alpha when comparing
|
|
12668
|
+
return !!color && 'r' in color && color.r === 0 && color.g === 0 && color.b === 255;
|
|
12669
|
+
}
|
|
12670
|
+
function decodeGridColor(color, defaultColor) {
|
|
12671
|
+
try {
|
|
12672
|
+
return color ? decodeColor(color) : defaultColor;
|
|
12673
|
+
}
|
|
12674
|
+
catch (_a) {
|
|
12675
|
+
return defaultColor; // don't fail whole text layer because of invalid grid color
|
|
12676
|
+
}
|
|
12677
|
+
}
|
|
12678
|
+
function decodeGridInfo(grid) {
|
|
12679
|
+
var _a, _b;
|
|
12680
|
+
if (!grid || typeof grid !== 'object')
|
|
12681
|
+
return undefined;
|
|
12682
|
+
const result = {
|
|
12683
|
+
isOn: !!grid.GridIsOn,
|
|
12684
|
+
show: !!grid.ShowGrid,
|
|
12685
|
+
size: (_a = grid.GridSize) !== null && _a !== void 0 ? _a : defaultGridInfo.size,
|
|
12686
|
+
leading: (_b = grid.GridLeading) !== null && _b !== void 0 ? _b : defaultGridInfo.leading,
|
|
12687
|
+
color: decodeGridColor(grid.GridColor, defaultGridInfo.color),
|
|
12688
|
+
leadingFillColor: decodeGridColor(grid.GridLeadingFillColor, defaultGridInfo.leadingFillColor),
|
|
12689
|
+
alignLineHeightToGridFlags: !!grid.AlignLineHeightToGridFlags,
|
|
12690
|
+
};
|
|
12691
|
+
const isDefault = !result.isOn && !result.show && result.size === defaultGridInfo.size &&
|
|
12692
|
+
result.leading === defaultGridInfo.leading && !result.alignLineHeightToGridFlags &&
|
|
12693
|
+
isDefaultGridColor(result.color) && isDefaultGridColor(result.leadingFillColor);
|
|
12694
|
+
return isDefault ? undefined : result;
|
|
12695
|
+
}
|
|
12023
12696
|
function decodeEngineData(engineData) {
|
|
12024
|
-
var _a, _b, _c, _d, _e, _f;
|
|
12697
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
12025
12698
|
// console.log('engineData', require('util').inspect(engineData, false, 99, true));
|
|
12026
12699
|
const engineDict = engineData.EngineDict;
|
|
12027
12700
|
const resourceDict = engineData.ResourceDict;
|
|
@@ -12033,9 +12706,11 @@ function decodeEngineData(engineData) {
|
|
|
12033
12706
|
}));
|
|
12034
12707
|
let text = engineDict.Editor.Text.replace(/\r/g, '\n');
|
|
12035
12708
|
let removedCharacters = 0;
|
|
12036
|
-
|
|
12709
|
+
// Photoshop always appends exactly one trailing \r (and encoder adds one back), any additional
|
|
12710
|
+
// trailing new lines are empty paragraphs that are part of the text
|
|
12711
|
+
if (/\n$/.test(text)) {
|
|
12037
12712
|
text = text.substring(0, text.length - 1);
|
|
12038
|
-
removedCharacters
|
|
12713
|
+
removedCharacters = 1;
|
|
12039
12714
|
}
|
|
12040
12715
|
const result = {
|
|
12041
12716
|
text,
|
|
@@ -12056,6 +12731,10 @@ function decodeEngineData(engineData) {
|
|
|
12056
12731
|
if (photoshop.BoxBounds)
|
|
12057
12732
|
result.boxBounds = photoshop.BoxBounds;
|
|
12058
12733
|
}
|
|
12734
|
+
// grid info (only included when it differs from defaults, to avoid noise in common case)
|
|
12735
|
+
const gridInfo = decodeGridInfo(engineDict.GridInfo);
|
|
12736
|
+
if (gridInfo)
|
|
12737
|
+
result.gridInfo = gridInfo;
|
|
12059
12738
|
// paragraph style
|
|
12060
12739
|
// const theNormalParagraphSheet = resourceDict.TheNormalParagraphSheet;
|
|
12061
12740
|
// const paragraphSheetSet = resourceDict.ParagraphSheetSet;
|
|
@@ -12086,13 +12765,17 @@ function decodeEngineData(engineData) {
|
|
|
12086
12765
|
// const styleSheetSet = resourceDict.StyleSheetSet;
|
|
12087
12766
|
// const styleSheetData = styleSheetSet[theNormalStyleSheet].StyleSheetData;
|
|
12088
12767
|
const styleRun = engineDict.StyleRun;
|
|
12768
|
+
// style runs without a font use the font of the normal style sheet
|
|
12769
|
+
const normalStyleSheet = (_j = (_g = resourceDict.StyleSheetSet) === null || _g === void 0 ? void 0 : _g[(_h = resourceDict.TheNormalStyleSheet) !== null && _h !== void 0 ? _h : 0]) === null || _j === void 0 ? void 0 : _j.StyleSheetData;
|
|
12770
|
+
const normalFontIndex = normalStyleSheet === null || normalStyleSheet === void 0 ? void 0 : normalStyleSheet.Font;
|
|
12771
|
+
const normalFont = (_k = (normalFontIndex !== undefined ? fonts[normalFontIndex] : undefined)) !== null && _k !== void 0 ? _k : fonts[0];
|
|
12089
12772
|
result.style = {}; // decodeStyle(styleSheetData, fonts);
|
|
12090
12773
|
result.styleRuns = [];
|
|
12091
12774
|
for (let i = 0; i < styleRun.RunArray.length; i++) {
|
|
12092
12775
|
const length = styleRun.RunLengthArray[i];
|
|
12093
12776
|
const style = decodeStyle(styleRun.RunArray[i].StyleSheet.StyleSheetData, fonts);
|
|
12094
|
-
if (!style.font)
|
|
12095
|
-
style.font =
|
|
12777
|
+
if (!style.font && normalFont)
|
|
12778
|
+
style.font = normalFont;
|
|
12096
12779
|
result.styleRuns.push({ length, style });
|
|
12097
12780
|
}
|
|
12098
12781
|
for (let counter = removedCharacters; result.styleRuns.length && counter > 0; counter--) {
|
|
@@ -12105,16 +12788,42 @@ function decodeEngineData(engineData) {
|
|
|
12105
12788
|
delete result.styleRuns;
|
|
12106
12789
|
return result;
|
|
12107
12790
|
}
|
|
12791
|
+
// Adjusts run lengths (specified in terms of the original text) for characters removed from the text
|
|
12792
|
+
// (\r characters of \r\n pairs that are collapsed into single \r)
|
|
12793
|
+
function adjustRunLengths(runs, removed) {
|
|
12794
|
+
if (!runs || !removed.length)
|
|
12795
|
+
return runs;
|
|
12796
|
+
let start = 0;
|
|
12797
|
+
let removedIndex = 0;
|
|
12798
|
+
return runs.map(run => {
|
|
12799
|
+
const length = Math.max(0, run.length || 0);
|
|
12800
|
+
const end = start + length;
|
|
12801
|
+
let count = 0;
|
|
12802
|
+
while (removedIndex < removed.length && removed[removedIndex] < end) {
|
|
12803
|
+
if (removed[removedIndex] >= start)
|
|
12804
|
+
count++;
|
|
12805
|
+
removedIndex++;
|
|
12806
|
+
}
|
|
12807
|
+
start = end;
|
|
12808
|
+
return Object.assign(Object.assign({}, run), { length: length - count });
|
|
12809
|
+
});
|
|
12810
|
+
}
|
|
12108
12811
|
function encodeEngineData(data) {
|
|
12109
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
12110
|
-
const
|
|
12812
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
12813
|
+
const sourceText = data.text || '';
|
|
12814
|
+
const removedIndices = []; // indices of \r characters removed from \r\n pairs
|
|
12815
|
+
for (let i = 0; i < sourceText.length - 1; i++) {
|
|
12816
|
+
if (sourceText.charCodeAt(i) === 13 && sourceText.charCodeAt(i + 1) === 10)
|
|
12817
|
+
removedIndices.push(i);
|
|
12818
|
+
}
|
|
12819
|
+
const text = `${sourceText.replace(/\r?\n/g, '\r')}\r`;
|
|
12111
12820
|
const fonts = [
|
|
12112
12821
|
{ name: 'AdobeInvisFont', script: 0, type: 0, synthetic: 0 },
|
|
12113
12822
|
];
|
|
12114
12823
|
const defFont = ((_a = data.style) === null || _a === void 0 ? void 0 : _a.font) || ((_c = (_b = data.styleRuns) === null || _b === void 0 ? void 0 : _b.find(s => s.style.font)) === null || _c === void 0 ? void 0 : _c.style.font) || defaultFont;
|
|
12115
12824
|
const paragraphRunArray = [];
|
|
12116
12825
|
const paragraphRunLengthArray = [];
|
|
12117
|
-
const paragraphRuns = data.paragraphStyleRuns;
|
|
12826
|
+
const paragraphRuns = adjustRunLengths(data.paragraphStyleRuns, removedIndices);
|
|
12118
12827
|
if (paragraphRuns && paragraphRuns.length) {
|
|
12119
12828
|
let leftLength = text.length;
|
|
12120
12829
|
for (const run of paragraphRuns) {
|
|
@@ -12163,7 +12872,9 @@ function encodeEngineData(data) {
|
|
|
12163
12872
|
}
|
|
12164
12873
|
}
|
|
12165
12874
|
const styleSheetData = encodeStyle(Object.assign(Object.assign({}, defaultStyle), { font: defFont }), fonts);
|
|
12166
|
-
const styleRuns = data.styleRuns ||
|
|
12875
|
+
const styleRuns = ((_d = data.styleRuns) === null || _d === void 0 ? void 0 : _d.length) ?
|
|
12876
|
+
adjustRunLengths(data.styleRuns, removedIndices) :
|
|
12877
|
+
[{ length: text.length, style: data.style || {} }];
|
|
12167
12878
|
const styleRunArray = [];
|
|
12168
12879
|
const styleRunLengthArray = [];
|
|
12169
12880
|
let leftLength = text.length;
|
|
@@ -12185,7 +12896,7 @@ function encodeEngineData(data) {
|
|
|
12185
12896
|
});
|
|
12186
12897
|
}
|
|
12187
12898
|
// add extra run to the end if existing ones didn't fill it up
|
|
12188
|
-
if (leftLength
|
|
12899
|
+
if (leftLength) {
|
|
12189
12900
|
styleRunLengthArray.push(leftLength);
|
|
12190
12901
|
styleRunArray.push({
|
|
12191
12902
|
StyleSheet: {
|
|
@@ -12194,6 +12905,7 @@ function encodeEngineData(data) {
|
|
|
12194
12905
|
});
|
|
12195
12906
|
}
|
|
12196
12907
|
const gridInfo = Object.assign(Object.assign({}, defaultGridInfo), data.gridInfo);
|
|
12908
|
+
const antiAliasIndex = antialias.indexOf((_e = data.antiAlias) !== null && _e !== void 0 ? _e : 'sharp');
|
|
12197
12909
|
const WritingDirection = data.orientation === 'vertical' ? 2 : 0;
|
|
12198
12910
|
const Procession = data.orientation === 'vertical' ? 1 : 0;
|
|
12199
12911
|
const ShapeType = data.shapeType === 'box' ? 1 : 0;
|
|
@@ -12257,11 +12969,11 @@ function encodeEngineData(data) {
|
|
|
12257
12969
|
FontType: f.type || 0,
|
|
12258
12970
|
Synthetic: f.synthetic || 0,
|
|
12259
12971
|
})),
|
|
12260
|
-
SuperscriptSize: (
|
|
12261
|
-
SuperscriptPosition: (
|
|
12262
|
-
SubscriptSize: (
|
|
12263
|
-
SubscriptPosition: (
|
|
12264
|
-
SmallCapSize: (
|
|
12972
|
+
SuperscriptSize: (_f = data.superscriptSize) !== null && _f !== void 0 ? _f : 0.583,
|
|
12973
|
+
SuperscriptPosition: (_g = data.superscriptPosition) !== null && _g !== void 0 ? _g : 0.333,
|
|
12974
|
+
SubscriptSize: (_h = data.subscriptSize) !== null && _h !== void 0 ? _h : 0.583,
|
|
12975
|
+
SubscriptPosition: (_j = data.subscriptPosition) !== null && _j !== void 0 ? _j : 0.333,
|
|
12976
|
+
SmallCapSize: (_k = data.smallCapSize) !== null && _k !== void 0 ? _k : 0.7,
|
|
12265
12977
|
};
|
|
12266
12978
|
const engineData = {
|
|
12267
12979
|
EngineDict: {
|
|
@@ -12284,14 +12996,14 @@ function encodeEngineData(data) {
|
|
|
12284
12996
|
GridInfo: {
|
|
12285
12997
|
GridIsOn: !!gridInfo.isOn,
|
|
12286
12998
|
ShowGrid: !!gridInfo.show,
|
|
12287
|
-
GridSize: (
|
|
12288
|
-
GridLeading: (
|
|
12999
|
+
GridSize: (_l = gridInfo.size) !== null && _l !== void 0 ? _l : 18,
|
|
13000
|
+
GridLeading: (_m = gridInfo.leading) !== null && _m !== void 0 ? _m : 22,
|
|
12289
13001
|
GridColor: encodeColor(gridInfo.color),
|
|
12290
|
-
GridLeadingFillColor: encodeColor(gridInfo.
|
|
13002
|
+
GridLeadingFillColor: encodeColor(gridInfo.leadingFillColor),
|
|
12291
13003
|
AlignLineHeightToGridFlags: !!gridInfo.alignLineHeightToGridFlags,
|
|
12292
13004
|
},
|
|
12293
|
-
AntiAlias:
|
|
12294
|
-
UseFractionalGlyphWidths: (
|
|
13005
|
+
AntiAlias: antiAliasIndex === -1 ? antialias.indexOf('sharp') : antiAliasIndex,
|
|
13006
|
+
UseFractionalGlyphWidths: (_o = data.useFractionalGlyphWidths) !== null && _o !== void 0 ? _o : true,
|
|
12295
13007
|
Rendered: {
|
|
12296
13008
|
Version: 1,
|
|
12297
13009
|
Shapes: {
|
|
@@ -12314,7 +13026,7 @@ function encodeEngineData(data) {
|
|
|
12314
13026
|
return engineData;
|
|
12315
13027
|
}
|
|
12316
13028
|
|
|
12317
|
-
},{}],16:[function(require,module,exports){
|
|
13029
|
+
},{"./helpers":8}],16:[function(require,module,exports){
|
|
12318
13030
|
"use strict";
|
|
12319
13031
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12320
13032
|
exports.stringLengthInBytes = stringLengthInBytes;
|
|
@@ -12335,30 +13047,44 @@ function charLengthInBytes(code) {
|
|
|
12335
13047
|
return 4;
|
|
12336
13048
|
}
|
|
12337
13049
|
}
|
|
12338
|
-
//
|
|
13050
|
+
// Returns scalar value at index `i` (combining surrogate pairs), replacing unpaired surrogates with U+FFFD,
|
|
12339
13051
|
// matching how TextEncoder converts a string to a sequence of Unicode scalar values.
|
|
13052
|
+
// Values above 0xffff always take 2 UTF-16 code units.
|
|
12340
13053
|
function codePointAt(value, i) {
|
|
12341
13054
|
const code = value.charCodeAt(i);
|
|
13055
|
+
if (code < 0xd800 || code > 0xdfff)
|
|
13056
|
+
return code;
|
|
12342
13057
|
// high surrogate
|
|
12343
|
-
if (code
|
|
13058
|
+
if (code <= 0xdbff && (i + 1) < value.length) {
|
|
12344
13059
|
const extra = value.charCodeAt(i + 1);
|
|
12345
13060
|
// low surrogate
|
|
12346
13061
|
if (extra >= 0xdc00 && extra <= 0xdfff) {
|
|
12347
|
-
return
|
|
13062
|
+
return ((code & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
|
|
12348
13063
|
}
|
|
12349
13064
|
}
|
|
12350
13065
|
// unpaired surrogate (lone high or lone low)
|
|
12351
|
-
|
|
12352
|
-
return { code: 0xfffd, size: 1 };
|
|
12353
|
-
}
|
|
12354
|
-
return { code, size: 1 };
|
|
13066
|
+
return 0xfffd;
|
|
12355
13067
|
}
|
|
12356
13068
|
function stringLengthInBytes(value) {
|
|
12357
13069
|
let result = 0;
|
|
12358
|
-
for (let i = 0; i < value.length;) {
|
|
12359
|
-
const
|
|
12360
|
-
|
|
12361
|
-
|
|
13070
|
+
for (let i = 0; i < value.length; i++) {
|
|
13071
|
+
const code = value.charCodeAt(i);
|
|
13072
|
+
if (code < 0x80) {
|
|
13073
|
+
result += 1;
|
|
13074
|
+
}
|
|
13075
|
+
else if (code < 0x800) {
|
|
13076
|
+
result += 2;
|
|
13077
|
+
}
|
|
13078
|
+
else {
|
|
13079
|
+
const scalar = codePointAt(value, i);
|
|
13080
|
+
if (scalar > 0xffff) {
|
|
13081
|
+
result += 4;
|
|
13082
|
+
i++;
|
|
13083
|
+
}
|
|
13084
|
+
else {
|
|
13085
|
+
result += 3;
|
|
13086
|
+
}
|
|
13087
|
+
}
|
|
12362
13088
|
}
|
|
12363
13089
|
return result;
|
|
12364
13090
|
}
|
|
@@ -12387,10 +13113,17 @@ function writeCharacter(buffer, offset, code) {
|
|
|
12387
13113
|
return length;
|
|
12388
13114
|
}
|
|
12389
13115
|
function encodeStringTo(buffer, offset, value) {
|
|
12390
|
-
for (let i = 0; i < value.length;) {
|
|
12391
|
-
const
|
|
12392
|
-
|
|
12393
|
-
|
|
13116
|
+
for (let i = 0; i < value.length; i++) {
|
|
13117
|
+
const code = value.charCodeAt(i);
|
|
13118
|
+
if (code < 0x80) {
|
|
13119
|
+
buffer[offset++] = code;
|
|
13120
|
+
}
|
|
13121
|
+
else {
|
|
13122
|
+
const scalar = codePointAt(value, i);
|
|
13123
|
+
if (scalar > 0xffff)
|
|
13124
|
+
i++;
|
|
13125
|
+
offset += writeCharacter(buffer, offset, scalar);
|
|
13126
|
+
}
|
|
12394
13127
|
}
|
|
12395
13128
|
return offset;
|
|
12396
13129
|
}
|