ag-psd 24.0.0 → 26.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/v22.13.1-x64-00250a7c/4511bacf +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/57d3380b +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/6cbfc0ec +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/7100ee08 +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/75e41e43 +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/8d0bf0b5 +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/acc36e66 +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/b3c2fab7 +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/c314aece +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/cfc49f4f +0 -0
- package/.v8-cache/v22.13.1-x64-00250a7c/e03e2acd +0 -0
- package/CHANGELOG.md +7 -0
- package/{TODO → TODO.md} +46 -0
- package/accept.js +18 -1
- package/dist/additionalInfo.js +62 -63
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +246 -186
- package/dist/descriptor.d.ts +4 -3
- package/dist/descriptor.js +9 -5
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +39 -5
- package/dist/imageResources.js.map +1 -1
- package/dist/psd.d.ts +12 -1
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.js +39 -36
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.js +96 -76
- package/dist/psdWriter.js.map +1 -1
- package/dist-es/additionalInfo.js +62 -63
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/descriptor.d.ts +4 -3
- package/dist-es/descriptor.js +9 -5
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +1 -0
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +41 -7
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/psd.d.ts +12 -1
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.js +39 -36
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.js +96 -76
- package/dist-es/psdWriter.js.map +1 -1
- package/package.json +1 -1
- package/src/additionalInfo.ts +66 -66
- package/src/descriptor.ts +12 -8
- package/src/helpers.ts +1 -0
- package/src/imageResources.ts +46 -20
- package/src/psd.ts +9 -1
- package/src/psdReader.ts +43 -40
- package/src/psdWriter.ts +92 -78
package/package.json
CHANGED
package/src/additionalInfo.ts
CHANGED
|
@@ -357,6 +357,17 @@ addHandler(
|
|
|
357
357
|
addHandlerAlias('vsms', 'vmsk');
|
|
358
358
|
// addHandlerAlias('vmsk', 'vsms');
|
|
359
359
|
|
|
360
|
+
addHandler(
|
|
361
|
+
'vowv', // something with vectors?
|
|
362
|
+
hasKey('vowv'),
|
|
363
|
+
(reader, target) => {
|
|
364
|
+
target.vowv = readUint32(reader); // always 2 ????
|
|
365
|
+
},
|
|
366
|
+
(writer, target) => {
|
|
367
|
+
writeUint32(writer, target.vowv!);
|
|
368
|
+
},
|
|
369
|
+
);
|
|
370
|
+
|
|
360
371
|
interface VogkDescriptor {
|
|
361
372
|
keyDescriptorList: {
|
|
362
373
|
keyShapeInvalidated?: boolean;
|
|
@@ -447,62 +458,59 @@ addHandler(
|
|
|
447
458
|
for (let i = 0; i < orig.keyDescriptorList.length; i++) {
|
|
448
459
|
const item = orig.keyDescriptorList[i];
|
|
449
460
|
|
|
450
|
-
|
|
451
|
-
desc.keyDescriptorList.push({ keyShapeInvalidated: true, keyOriginIndex: i });
|
|
452
|
-
} else {
|
|
453
|
-
desc.keyDescriptorList.push({} as any); // we're adding keyOriginIndex at the end
|
|
454
|
-
|
|
455
|
-
const out = desc.keyDescriptorList[desc.keyDescriptorList.length - 1];
|
|
461
|
+
desc.keyDescriptorList.push({} as any); // we're adding keyOriginIndex at the end
|
|
456
462
|
|
|
457
|
-
|
|
458
|
-
if (item.keyOriginResolution != null) out.keyOriginResolution = item.keyOriginResolution;
|
|
463
|
+
const out = desc.keyDescriptorList[desc.keyDescriptorList.length - 1];
|
|
459
464
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
out.keyOriginRRectRadii = {
|
|
463
|
-
unitValueQuadVersion: 1,
|
|
464
|
-
topRight: unitsValue(radii.topRight, 'topRight'),
|
|
465
|
-
topLeft: unitsValue(radii.topLeft, 'topLeft'),
|
|
466
|
-
bottomLeft: unitsValue(radii.bottomLeft, 'bottomLeft'),
|
|
467
|
-
bottomRight: unitsValue(radii.bottomRight, 'bottomRight'),
|
|
468
|
-
};
|
|
469
|
-
}
|
|
465
|
+
if (item.keyOriginType != null) out.keyOriginType = item.keyOriginType;
|
|
466
|
+
if (item.keyOriginResolution != null) out.keyOriginResolution = item.keyOriginResolution;
|
|
470
467
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
468
|
+
const radii = item.keyOriginRRectRadii;
|
|
469
|
+
if (radii) {
|
|
470
|
+
out.keyOriginRRectRadii = {
|
|
471
|
+
unitValueQuadVersion: 1,
|
|
472
|
+
topRight: unitsValue(radii.topRight, 'topRight'),
|
|
473
|
+
topLeft: unitsValue(radii.topLeft, 'topLeft'),
|
|
474
|
+
bottomLeft: unitsValue(radii.bottomLeft, 'bottomLeft'),
|
|
475
|
+
bottomRight: unitsValue(radii.bottomRight, 'bottomRight'),
|
|
476
|
+
};
|
|
477
|
+
}
|
|
481
478
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
479
|
+
const box = item.keyOriginShapeBoundingBox;
|
|
480
|
+
if (box) {
|
|
481
|
+
out.keyOriginShapeBBox = {
|
|
482
|
+
unitValueQuadVersion: 1,
|
|
483
|
+
'Top ': unitsValue(box.top, 'top'),
|
|
484
|
+
Left: unitsValue(box.left, 'left'),
|
|
485
|
+
Btom: unitsValue(box.bottom, 'bottom'),
|
|
486
|
+
Rght: unitsValue(box.right, 'right'),
|
|
487
|
+
};
|
|
488
|
+
}
|
|
491
489
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
};
|
|
502
|
-
}
|
|
490
|
+
const corners = item.keyOriginBoxCorners;
|
|
491
|
+
if (corners && corners.length === 4) {
|
|
492
|
+
out.keyOriginBoxCorners = {
|
|
493
|
+
rectangleCornerA: { Hrzn: corners[0].x, Vrtc: corners[0].y },
|
|
494
|
+
rectangleCornerB: { Hrzn: corners[1].x, Vrtc: corners[1].y },
|
|
495
|
+
rectangleCornerC: { Hrzn: corners[2].x, Vrtc: corners[2].y },
|
|
496
|
+
rectangleCornerD: { Hrzn: corners[3].x, Vrtc: corners[3].y },
|
|
497
|
+
};
|
|
498
|
+
}
|
|
503
499
|
|
|
504
|
-
|
|
500
|
+
const transform = item.transform;
|
|
501
|
+
if (transform && transform.length === 6) {
|
|
502
|
+
out.Trnf = {
|
|
503
|
+
xx: transform[0],
|
|
504
|
+
xy: transform[1],
|
|
505
|
+
yx: transform[2],
|
|
506
|
+
yy: transform[3],
|
|
507
|
+
tx: transform[4],
|
|
508
|
+
ty: transform[5],
|
|
509
|
+
};
|
|
505
510
|
}
|
|
511
|
+
|
|
512
|
+
if (item.keyShapeInvalidated != null) out.keyShapeInvalidated = item.keyShapeInvalidated;
|
|
513
|
+
out.keyOriginIndex = i;
|
|
506
514
|
}
|
|
507
515
|
|
|
508
516
|
writeInt32(writer, 1); // version
|
|
@@ -1128,7 +1136,13 @@ function encodeWarp(warp: Warp): WarpDescriptor {
|
|
|
1128
1136
|
warpPerspective: warp.perspective || 0,
|
|
1129
1137
|
warpPerspectiveOther: warp.perspectiveOther || 0,
|
|
1130
1138
|
warpRotate: Ornt.encode(warp.rotate),
|
|
1131
|
-
bounds: {
|
|
1139
|
+
bounds: /*1 ? { // testing
|
|
1140
|
+
_classID: 'classFloatRect',
|
|
1141
|
+
'Top ': bounds && bounds.top && bounds.top.value || 0,
|
|
1142
|
+
Left: bounds && bounds.left && bounds.left.value || 0,
|
|
1143
|
+
Btom: bounds && bounds.bottom && bounds.bottom.value || 0,
|
|
1144
|
+
Rght: bounds && bounds.right && bounds.right.value || 0,
|
|
1145
|
+
} :*/ {
|
|
1132
1146
|
'Top ': unitsValue(bounds && bounds.top || { units: 'Pixels', value: 0 }, 'bounds.top'),
|
|
1133
1147
|
Left: unitsValue(bounds && bounds.left || { units: 'Pixels', value: 0 }, 'bounds.left'),
|
|
1134
1148
|
Btom: unitsValue(bounds && bounds.bottom || { units: 'Pixels', value: 0 }, 'bounds.bottom'),
|
|
@@ -1315,7 +1329,7 @@ type SoLdDescriptorFilterItem = {
|
|
|
1315
1329
|
} | {
|
|
1316
1330
|
filterID: 1198747202;
|
|
1317
1331
|
Fltr: {
|
|
1318
|
-
_name: 'Gaussian Blur';
|
|
1332
|
+
_name: 'Gaussian Blur' | '高斯模糊';
|
|
1319
1333
|
_classID: 'GsnB';
|
|
1320
1334
|
'Rds ': DescriptorUnitsValue;
|
|
1321
1335
|
};
|
|
@@ -2636,6 +2650,7 @@ function serializeFilterFXItem(f: Filter): SoLdDescriptorFilterItem {
|
|
|
2636
2650
|
case 'gaussian blur': return {
|
|
2637
2651
|
...base,
|
|
2638
2652
|
Fltr: {
|
|
2653
|
+
// _name: '高斯模糊', // Testing
|
|
2639
2654
|
_name: 'Gaussian Blur',
|
|
2640
2655
|
_classID: 'GsnB',
|
|
2641
2656
|
'Rds ': uvRadius(f.filter),
|
|
@@ -3542,21 +3557,6 @@ addHandler(
|
|
|
3542
3557
|
},
|
|
3543
3558
|
);
|
|
3544
3559
|
|
|
3545
|
-
if (MOCK_HANDLERS) {
|
|
3546
|
-
addHandler(
|
|
3547
|
-
'vowv', // appears with Lr16 section ?
|
|
3548
|
-
_ => false,
|
|
3549
|
-
(reader, target, left) => {
|
|
3550
|
-
const value = readUint32(reader); // always 2 ????
|
|
3551
|
-
reader; target;
|
|
3552
|
-
console.log('vowv', { value }, left());
|
|
3553
|
-
},
|
|
3554
|
-
(_writer, _target) => {
|
|
3555
|
-
// TODO: write
|
|
3556
|
-
},
|
|
3557
|
-
);
|
|
3558
|
-
}
|
|
3559
|
-
|
|
3560
3560
|
if (MOCK_HANDLERS) {
|
|
3561
3561
|
addHandler(
|
|
3562
3562
|
'Patt',
|
package/src/descriptor.ts
CHANGED
|
@@ -56,12 +56,14 @@ function makeType(name: string, classID: string) {
|
|
|
56
56
|
|
|
57
57
|
const nullType = makeType('', 'null');
|
|
58
58
|
|
|
59
|
+
const USE_CHINESE = false; // Testing
|
|
60
|
+
|
|
59
61
|
const fieldToExtType: ExtTypeDict = {
|
|
60
62
|
strokeStyleContent: makeType('', 'solidColorLayer'),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
printProofSetup: makeType(USE_CHINESE ? '校样设置' : 'Proof Setup', 'proofSetup'),
|
|
64
|
+
Grad: makeType(USE_CHINESE ? '渐变' : 'Gradient', 'Grdn'),
|
|
65
|
+
Trnf: makeType(USE_CHINESE ? '变换' : 'Transform', 'Trnf'),
|
|
63
66
|
patternFill: makeType('', 'patternFill'),
|
|
64
|
-
Grad: makeType('Gradient', 'Grdn'),
|
|
65
67
|
ebbl: makeType('', 'ebbl'),
|
|
66
68
|
SoFi: makeType('', 'SoFi'),
|
|
67
69
|
GrFl: makeType('', 'GrFl'),
|
|
@@ -103,7 +105,6 @@ const fieldToExtType: ExtTypeDict = {
|
|
|
103
105
|
rectangleCornerC: makeType('', 'Pnt '),
|
|
104
106
|
rectangleCornerD: makeType('', 'Pnt '),
|
|
105
107
|
compInfo: nullType,
|
|
106
|
-
Trnf: makeType('Transform', 'Trnf'),
|
|
107
108
|
quiltWarp: makeType('', 'quiltWarp'),
|
|
108
109
|
generatorSettings: nullType,
|
|
109
110
|
crema: nullType,
|
|
@@ -208,7 +209,7 @@ const typeToField: { [key: string]: string[]; } = {
|
|
|
208
209
|
'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
|
|
209
210
|
'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
|
|
210
211
|
'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
|
|
211
|
-
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion',
|
|
212
|
+
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
|
|
212
213
|
],
|
|
213
214
|
'bool': [
|
|
214
215
|
'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
|
|
@@ -879,11 +880,12 @@ export interface DescriptorColorContent {
|
|
|
879
880
|
}
|
|
880
881
|
|
|
881
882
|
export interface DescriptorGradientContent {
|
|
882
|
-
Grad: DesciptorGradient;
|
|
883
|
-
Type: string;
|
|
884
883
|
Dthr?: boolean;
|
|
885
|
-
|
|
884
|
+
gradientsInterpolationMethod?: string; // 'gradientInterpolationMethodType.Smoo'
|
|
886
885
|
Angl?: DescriptorUnitsValue;
|
|
886
|
+
Type: string;
|
|
887
|
+
Grad: DesciptorGradient;
|
|
888
|
+
Rvrs?: boolean;
|
|
887
889
|
'Scl '?: DescriptorUnitsValue;
|
|
888
890
|
Algn?: boolean;
|
|
889
891
|
Ofst?: { Hrzn: DescriptorUnitsValue; Vrtc: DescriptorUnitsValue; };
|
|
@@ -1611,6 +1613,7 @@ function parseGradientContent(descriptor: DescriptorGradientContent) {
|
|
|
1611
1613
|
const result = parseGradient(descriptor.Grad) as (EffectSolidGradient | EffectNoiseGradient) & ExtraGradientInfo;
|
|
1612
1614
|
result.style = GrdT.decode(descriptor.Type);
|
|
1613
1615
|
if (descriptor.Dthr !== undefined) result.dither = descriptor.Dthr;
|
|
1616
|
+
if (descriptor.gradientsInterpolationMethod !== undefined) result.interpolationMethod = gradientInterpolationMethodType.decode(descriptor.gradientsInterpolationMethod);
|
|
1614
1617
|
if (descriptor.Rvrs !== undefined) result.reverse = descriptor.Rvrs;
|
|
1615
1618
|
if (descriptor.Angl !== undefined) result.angle = parseAngle(descriptor.Angl);
|
|
1616
1619
|
if (descriptor['Scl '] !== undefined) result.scale = parsePercent(descriptor['Scl ']);
|
|
@@ -1650,6 +1653,7 @@ export function parseVectorContent(descriptor: DescriptorVectorContent): VectorC
|
|
|
1650
1653
|
function serializeGradientContent(content: (EffectSolidGradient | EffectNoiseGradient) & ExtraGradientInfo) {
|
|
1651
1654
|
const result: DescriptorGradientContent = {} as any;
|
|
1652
1655
|
if (content.dither !== undefined) result.Dthr = content.dither;
|
|
1656
|
+
if (content.interpolationMethod !== undefined) result.gradientsInterpolationMethod = gradientInterpolationMethodType.encode(content.interpolationMethod);
|
|
1653
1657
|
if (content.reverse !== undefined) result.Rvrs = content.reverse;
|
|
1654
1658
|
if (content.angle !== undefined) result.Angl = unitsAngle(content.angle);
|
|
1655
1659
|
result.Type = GrdT.encode(content.style);
|
package/src/helpers.ts
CHANGED
package/src/imageResources.ts
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { toByteArray } from 'base64-js';
|
|
2
2
|
import { BlendMode, ImageResources, RenderingIntent } from './psd';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
readBytes, skipBytes, readFloat32, readInt16, readFixedPoint32, readSignature, checkSignature,
|
|
6
|
-
readSection, readColor, readInt32
|
|
7
|
-
} from './psdReader';
|
|
8
|
-
import {
|
|
9
|
-
PsdWriter, writePascalString, writeUnicodeString, writeUint32, writeUint8, writeFloat64, writeUint16,
|
|
10
|
-
writeBytes, writeInt16, writeFloat32, writeFixedPoint32, writeUnicodeStringWithPadding, writeColor, writeSignature,
|
|
11
|
-
writeSection, writeInt32,
|
|
12
|
-
} from './psdWriter';
|
|
3
|
+
import { PsdReader, readUnicodeString, readUint32, readUint16, readUint8, readFloat64, readBytes, skipBytes, readFloat32, readInt16, readFixedPoint32, readSignature, checkSignature, readSection, readColor, readInt32 } from './psdReader';
|
|
4
|
+
import { PsdWriter, writeUnicodeString, writeUint32, writeUint8, writeFloat64, writeUint16, writeBytes, writeInt16, writeFloat32, writeFixedPoint32, writeUnicodeStringWithPadding, writeColor, writeSignature, writeSection, writeInt32, } from './psdWriter';
|
|
13
5
|
import { createCanvasFromData, createEnum, MOCK_HANDLERS } from './helpers';
|
|
14
6
|
import { decodeString, encodeString } from './utf8';
|
|
15
|
-
import {
|
|
16
|
-
ESliceBGColorType, ESliceHorzAlign, ESliceOrigin, ESliceType, ESliceVertAlign, frac,
|
|
17
|
-
FractionDescriptor, parseTrackList, readVersionAndDescriptor, serializeTrackList, TimelineTrackDescriptor,
|
|
18
|
-
TimeScopeDescriptor, writeVersionAndDescriptor
|
|
19
|
-
} from './descriptor';
|
|
7
|
+
import { ESliceBGColorType, ESliceHorzAlign, ESliceOrigin, ESliceType, ESliceVertAlign, frac, FractionDescriptor, parseTrackList, readVersionAndDescriptor, serializeTrackList, TimelineTrackDescriptor, TimeScopeDescriptor, writeVersionAndDescriptor } from './descriptor';
|
|
20
8
|
|
|
21
9
|
export interface ResourceHandler {
|
|
22
10
|
key: number;
|
|
@@ -62,6 +50,38 @@ function writeUtf8String(writer: PsdWriter, value: string) {
|
|
|
62
50
|
writeBytes(writer, buffer);
|
|
63
51
|
}
|
|
64
52
|
|
|
53
|
+
function readEncodedString(reader: PsdReader) {
|
|
54
|
+
const length = readUint8(reader);
|
|
55
|
+
const buffer = readBytes(reader, length);
|
|
56
|
+
|
|
57
|
+
let notAscii = false;
|
|
58
|
+
for (let i = 0; i < buffer.byteLength; i++) {
|
|
59
|
+
if (buffer[i] & 0x80) {
|
|
60
|
+
notAscii = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (notAscii) {
|
|
66
|
+
const decoder = new TextDecoder('gbk');
|
|
67
|
+
return decoder.decode(buffer)
|
|
68
|
+
} else {
|
|
69
|
+
return decodeString(buffer);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function writeEncodedString(writer: PsdWriter, value: string) {
|
|
74
|
+
let ascii = '';
|
|
75
|
+
|
|
76
|
+
for (let i = 0, code = value.codePointAt(i++); code !== undefined; code = value.codePointAt(i++)) {
|
|
77
|
+
ascii += code > 0x7f ? '?' : String.fromCodePoint(code);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const buffer = encodeString(ascii);
|
|
81
|
+
writeUint8(writer, buffer.byteLength);
|
|
82
|
+
writeBytes(writer, buffer);
|
|
83
|
+
}
|
|
84
|
+
|
|
65
85
|
MOCK_HANDLERS && addHandler(
|
|
66
86
|
1028, // IPTC-NAA record
|
|
67
87
|
target => (target as any)._ir1028 !== undefined,
|
|
@@ -273,16 +293,22 @@ addHandler(
|
|
|
273
293
|
1006,
|
|
274
294
|
target => target.alphaChannelNames !== undefined,
|
|
275
295
|
(reader, target, left) => {
|
|
276
|
-
target.alphaChannelNames
|
|
296
|
+
if (!target.alphaChannelNames) { // skip if the unicode versions are already read
|
|
297
|
+
target.alphaChannelNames = [];
|
|
277
298
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
299
|
+
while (left() > 0) {
|
|
300
|
+
const value = readEncodedString(reader);
|
|
301
|
+
// const value = readPascalString(reader, 1);
|
|
302
|
+
target.alphaChannelNames.push(value);
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
skipBytes(reader, left());
|
|
281
306
|
}
|
|
282
307
|
},
|
|
283
308
|
(writer, target) => {
|
|
284
309
|
for (const name of target.alphaChannelNames!) {
|
|
285
|
-
|
|
310
|
+
writeEncodedString(writer, name);
|
|
311
|
+
// writePascalString(writer, name, 1);
|
|
286
312
|
}
|
|
287
313
|
},
|
|
288
314
|
);
|
package/src/psd.ts
CHANGED
|
@@ -264,7 +264,7 @@ export type Justification = 'left' | 'right' | 'center' | 'justify-left' | 'just
|
|
|
264
264
|
export type LineCapType = 'butt' | 'round' | 'square';
|
|
265
265
|
export type LineJoinType = 'miter' | 'round' | 'bevel';
|
|
266
266
|
export type LineAlignment = 'inside' | 'center' | 'outside';
|
|
267
|
-
export type InterpolationMethod = 'classic' | 'perceptual' | 'linear';
|
|
267
|
+
export type InterpolationMethod = 'classic' | 'perceptual' | 'linear' | 'smooth';
|
|
268
268
|
|
|
269
269
|
export interface Warp {
|
|
270
270
|
style?: WarpStyle;
|
|
@@ -457,6 +457,7 @@ export interface ExtraGradientInfo {
|
|
|
457
457
|
scale?: number;
|
|
458
458
|
angle?: number;
|
|
459
459
|
dither?: boolean;
|
|
460
|
+
interpolationMethod?: InterpolationMethod;
|
|
460
461
|
reverse?: boolean;
|
|
461
462
|
align?: boolean;
|
|
462
463
|
offset?: { x: number; y: number; };
|
|
@@ -1322,6 +1323,7 @@ export interface LayerAdditionalInfo {
|
|
|
1322
1323
|
id?: number; // layer id
|
|
1323
1324
|
version?: number; // layer version
|
|
1324
1325
|
mask?: LayerMaskData;
|
|
1326
|
+
realMask?: LayerMaskData;
|
|
1325
1327
|
blendClippendElements?: boolean; // has to be set to `true` when using `color burn` blend mode (otherwise `transparencyShapesLayer` is set incorrectly)
|
|
1326
1328
|
blendInteriorElements?: boolean;
|
|
1327
1329
|
knockout?: boolean;
|
|
@@ -1441,6 +1443,12 @@ export interface LayerAdditionalInfo {
|
|
|
1441
1443
|
colorSpace: Color;
|
|
1442
1444
|
opacity: number;
|
|
1443
1445
|
};
|
|
1446
|
+
blendingRanges?: {
|
|
1447
|
+
compositeGrayBlendSource: number[];
|
|
1448
|
+
compositeGraphBlendDestinationRange: number[];
|
|
1449
|
+
ranges: { sourceRange: number[]; destRange: number[]; }[];
|
|
1450
|
+
};
|
|
1451
|
+
vowv?: number; // ???
|
|
1444
1452
|
|
|
1445
1453
|
// Base64 encoded raw EngineData, currently just kept in original state to support
|
|
1446
1454
|
// loading and modifying PSD file without breaking text layers.
|
package/src/psdReader.ts
CHANGED
|
@@ -326,7 +326,7 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
if (left() >= 12) {
|
|
329
|
-
readAdditionalLayerInfo(reader, psd, psd
|
|
329
|
+
readAdditionalLayerInfo(reader, psd, psd);
|
|
330
330
|
} else {
|
|
331
331
|
// opt.logMissingFeatures && console.log('skipping leftover bytes', left());
|
|
332
332
|
skipBytes(reader, left());
|
|
@@ -443,10 +443,10 @@ function readLayerRecord(reader: PsdReader, psd: Psd) {
|
|
|
443
443
|
skipBytes(reader, 1);
|
|
444
444
|
|
|
445
445
|
readSection(reader, 1, left => {
|
|
446
|
-
|
|
447
|
-
if (mask) layer.mask = mask;
|
|
446
|
+
readLayerMaskData(reader, layer);
|
|
448
447
|
|
|
449
|
-
|
|
448
|
+
const blendingRanges = readLayerBlendingRanges(reader);
|
|
449
|
+
if (blendingRanges) layer.blendingRanges = blendingRanges;
|
|
450
450
|
layer.name = readPascalString(reader, 1); // should be padded to 4, but is not sometimes
|
|
451
451
|
|
|
452
452
|
// HACK: fix for sometimes layer.name string not being padded correctly, just skip until we get valid signature
|
|
@@ -460,11 +460,13 @@ function readLayerRecord(reader: PsdReader, psd: Psd) {
|
|
|
460
460
|
return { layer, channels };
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
-
function readLayerMaskData(reader: PsdReader) {
|
|
463
|
+
function readLayerMaskData(reader: PsdReader, layer: Layer) {
|
|
464
464
|
return readSection<LayerMaskData | undefined>(reader, 1, left => {
|
|
465
465
|
if (!left()) return undefined;
|
|
466
466
|
|
|
467
467
|
const mask: LayerMaskData = {};
|
|
468
|
+
layer.mask = mask;
|
|
469
|
+
|
|
468
470
|
mask.top = readInt32(reader);
|
|
469
471
|
mask.left = readInt32(reader);
|
|
470
472
|
mask.bottom = readInt32(reader);
|
|
@@ -476,6 +478,22 @@ function readLayerMaskData(reader: PsdReader) {
|
|
|
476
478
|
mask.disabled = (flags & LayerMaskFlags.LayerMaskDisabled) !== 0;
|
|
477
479
|
mask.fromVectorData = (flags & LayerMaskFlags.LayerMaskFromRenderingOtherData) !== 0;
|
|
478
480
|
|
|
481
|
+
if (left() >= 18) {
|
|
482
|
+
const realMask: LayerMaskData = {};
|
|
483
|
+
layer.realMask = realMask;
|
|
484
|
+
|
|
485
|
+
const realFlags = readUint8(reader);
|
|
486
|
+
realMask.positionRelativeToLayer = (realFlags & LayerMaskFlags.PositionRelativeToLayer) !== 0;
|
|
487
|
+
realMask.disabled = (realFlags & LayerMaskFlags.LayerMaskDisabled) !== 0;
|
|
488
|
+
realMask.fromVectorData = (realFlags & LayerMaskFlags.LayerMaskFromRenderingOtherData) !== 0;
|
|
489
|
+
|
|
490
|
+
realMask.defaultColor = readUint8(reader); // Real user mask background. 0 or 255.
|
|
491
|
+
realMask.top = readInt32(reader);
|
|
492
|
+
realMask.left = readInt32(reader);
|
|
493
|
+
realMask.bottom = readInt32(reader);
|
|
494
|
+
realMask.right = readInt32(reader);
|
|
495
|
+
}
|
|
496
|
+
|
|
479
497
|
if (flags & LayerMaskFlags.MaskHasParametersAppliedToIt) {
|
|
480
498
|
const params = readUint8(reader);
|
|
481
499
|
if (params & MaskParams.UserMaskDensity) mask.userMaskDensity = readUint8(reader) / 0xff;
|
|
@@ -484,37 +502,23 @@ function readLayerMaskData(reader: PsdReader) {
|
|
|
484
502
|
if (params & MaskParams.VectorMaskFeather) mask.vectorMaskFeather = readFloat64(reader);
|
|
485
503
|
}
|
|
486
504
|
|
|
487
|
-
if (left() > 2) {
|
|
488
|
-
// TODO: handle these values, this is RealUserMask
|
|
489
|
-
/*const realFlags = readUint8(reader);
|
|
490
|
-
const realUserMaskBackground = readUint8(reader);
|
|
491
|
-
const top2 = readInt32(reader);
|
|
492
|
-
const left2 = readInt32(reader);
|
|
493
|
-
const bottom2 = readInt32(reader);
|
|
494
|
-
const right2 = readInt32(reader);
|
|
495
|
-
|
|
496
|
-
// TEMP
|
|
497
|
-
(mask as any)._real = { realFlags, realUserMaskBackground, top2, left2, bottom2, right2 };*/
|
|
498
|
-
|
|
499
|
-
if (reader.logMissingFeatures) {
|
|
500
|
-
reader.log('Unhandled extra real user mask params');
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
505
|
skipBytes(reader, left());
|
|
505
|
-
return mask;
|
|
506
506
|
});
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
+
function readBlendingRange(reader: PsdReader) {
|
|
510
|
+
return [readUint8(reader), readUint8(reader), readUint8(reader), readUint8(reader)];
|
|
511
|
+
}
|
|
512
|
+
|
|
509
513
|
function readLayerBlendingRanges(reader: PsdReader) {
|
|
510
514
|
return readSection(reader, 1, left => {
|
|
511
|
-
const compositeGrayBlendSource =
|
|
512
|
-
const compositeGraphBlendDestinationRange =
|
|
513
|
-
const ranges = [];
|
|
515
|
+
const compositeGrayBlendSource = readBlendingRange(reader);
|
|
516
|
+
const compositeGraphBlendDestinationRange = readBlendingRange(reader);
|
|
517
|
+
const ranges: { sourceRange: number[]; destRange: number[]; }[] = [];
|
|
514
518
|
|
|
515
519
|
while (left() > 0) {
|
|
516
|
-
const sourceRange =
|
|
517
|
-
const destRange =
|
|
520
|
+
const sourceRange = readBlendingRange(reader);
|
|
521
|
+
const destRange = readBlendingRange(reader);
|
|
518
522
|
ranges.push({ sourceRange, destRange });
|
|
519
523
|
}
|
|
520
524
|
|
|
@@ -567,13 +571,13 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
|
|
|
567
571
|
|
|
568
572
|
if (compression > 3) throw new Error(`Invalid compression: ${compression}`);
|
|
569
573
|
|
|
570
|
-
if (channel.id === ChannelID.UserMask) {
|
|
571
|
-
const mask = layer.mask;
|
|
572
|
-
|
|
573
|
-
if (!mask) throw new Error(`Missing layer mask data`);
|
|
574
|
+
if (channel.id === ChannelID.UserMask || channel.id === ChannelID.RealUserMask) {
|
|
575
|
+
const mask = channel.id === ChannelID.UserMask ? layer.mask : layer.realMask;
|
|
576
|
+
if (!mask) throw new Error(`Missing layer ${channel.id === ChannelID.UserMask ? 'mask' : 'real mask'} data`);
|
|
574
577
|
|
|
575
578
|
const maskWidth = (mask.right || 0) - (mask.left || 0);
|
|
576
579
|
const maskHeight = (mask.bottom || 0) - (mask.top || 0);
|
|
580
|
+
if (maskWidth < 0 || maskHeight < 0 || maskWidth > 30000 || maskHeight > 30000) throw new Error('Invalid mask size');
|
|
577
581
|
|
|
578
582
|
if (maskWidth && maskHeight) {
|
|
579
583
|
const maskData = createImageDataBitDepth(maskWidth, maskHeight, psd.bitsPerChannel ?? 8);
|
|
@@ -583,8 +587,13 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
|
|
|
583
587
|
readData(reader, channel.length, maskData, compression, maskWidth, maskHeight, psd.bitsPerChannel ?? 8, 0, reader.large, 4);
|
|
584
588
|
|
|
585
589
|
if (RAW_IMAGE_DATA) {
|
|
586
|
-
(
|
|
587
|
-
|
|
590
|
+
if (channel.id === ChannelID.UserMask) {
|
|
591
|
+
(layer as any).maskDataRawCompression = compression;
|
|
592
|
+
(layer as any).maskDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
593
|
+
} else {
|
|
594
|
+
(layer as any).realMaskDataRawCompression = compression;
|
|
595
|
+
(layer as any).realMaskDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
596
|
+
}
|
|
588
597
|
}
|
|
589
598
|
|
|
590
599
|
setupGrayscale(maskData);
|
|
@@ -595,12 +604,6 @@ function readLayerChannelImageData(reader: PsdReader, psd: Psd, layer: Layer, ch
|
|
|
595
604
|
mask.canvas = imageDataToCanvas(maskData);
|
|
596
605
|
}
|
|
597
606
|
}
|
|
598
|
-
} else if (channel.id === ChannelID.RealUserMask) {
|
|
599
|
-
if (reader.logMissingFeatures) {
|
|
600
|
-
reader.log(`RealUserMask not supported`);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
reader.offset = start + channel.length;
|
|
604
607
|
} else {
|
|
605
608
|
const offset = offsetForChannel(channel.id, cmyk);
|
|
606
609
|
let targetData = imageData;
|