ag-psd
Version:
Library for reading and writing PSD files
1,168 lines (1,167 loc) • 78.2 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { createEnum } from './helpers';
import { readSignature, readUnicodeString, readUint32, readUint8, readFloat64, readBytes, readAsciiString, readInt32, readFloat32, readInt32LE, readUnicodeStringWithLengthLE } from './psdReader';
import { writeSignature, writeBytes, writeUint32, writeFloat64, writeUint8, writeUnicodeStringWithPadding, writeInt32, writeFloat32, writeUnicodeString, writeInt32LE, writeUnicodeStringWithoutLengthLE } from './psdWriter';
function revMap(map) {
var result = {};
Object.keys(map).forEach(function (key) { return result[map[key]] = key; });
return result;
}
var unitsMap = {
'#Ang': 'Angle',
'#Rsl': 'Density',
'#Rlt': 'Distance',
'#Nne': 'None',
'#Prc': 'Percent',
'#Pxl': 'Pixels',
'#Mlm': 'Millimeters',
'#Pnt': 'Points',
'RrPi': 'Picas',
'RrIn': 'Inches',
'RrCm': 'Centimeters',
};
var unitsMapRev = revMap(unitsMap);
var logErrors = false;
export function setLogErrors(value) {
logErrors = value;
}
function makeType(name, classID) {
return { name: name, classID: classID };
}
var nullType = makeType('', 'null');
var USE_CHINESE = false; // Testing
var fieldToExtType = {
strokeStyleContent: makeType('', 'solidColorLayer'),
printProofSetup: makeType(USE_CHINESE ? '校样设置' : 'Proof Setup', 'proofSetup'),
Grad: makeType(USE_CHINESE ? '渐变' : 'Gradient', 'Grdn'),
Trnf: makeType(USE_CHINESE ? '变换' : 'Transform', 'Trnf'),
patternFill: makeType('', 'patternFill'),
ebbl: makeType('', 'ebbl'),
SoFi: makeType('', 'SoFi'),
GrFl: makeType('', 'GrFl'),
sdwC: makeType('', 'RGBC'),
hglC: makeType('', 'RGBC'),
'Clr ': makeType('', 'RGBC'),
'tintColor': makeType('', 'RGBC'),
Ofst: makeType('', 'Pnt '),
ChFX: makeType('', 'ChFX'),
MpgS: makeType('', 'ShpC'),
DrSh: makeType('', 'DrSh'),
IrSh: makeType('', 'IrSh'),
OrGl: makeType('', 'OrGl'),
IrGl: makeType('', 'IrGl'),
TrnS: makeType('', 'ShpC'),
Ptrn: makeType('', 'Ptrn'),
FrFX: makeType('', 'FrFX'),
phase: makeType('', 'Pnt '),
frameStep: nullType,
duration: nullType,
workInTime: nullType,
workOutTime: nullType,
audioClipGroupList: nullType,
bounds: makeType('', 'Rctn'),
customEnvelopeWarp: makeType('', 'customEnvelopeWarp'),
warp: makeType('', 'warp'),
'Sz ': makeType('', 'Pnt '),
origin: makeType('', 'Pnt '),
autoExpandOffset: makeType('', 'Pnt '),
keyOriginShapeBBox: makeType('', 'unitRect'),
Vrsn: nullType,
psVersion: nullType,
docDefaultNewArtboardBackgroundColor: makeType('', 'RGBC'),
artboardRect: makeType('', 'classFloatRect'),
keyOriginRRectRadii: makeType('', 'radii'),
keyOriginBoxCorners: nullType,
rectangleCornerA: makeType('', 'Pnt '),
rectangleCornerB: makeType('', 'Pnt '),
rectangleCornerC: makeType('', 'Pnt '),
rectangleCornerD: makeType('', 'Pnt '),
compInfo: nullType,
quiltWarp: makeType('', 'quiltWarp'),
generatorSettings: nullType,
crema: nullType,
FrIn: nullType,
blendOptions: nullType,
FXRf: nullType,
Lefx: nullType,
time: nullType,
animKey: nullType,
timeScope: nullType,
inTime: nullType,
outTime: nullType,
sheetStyle: nullType,
translation: nullType,
Skew: nullType,
boundingBox: makeType('', 'boundingBox'),
'Lnk ': makeType('', 'ExternalFileLink'),
frameReader: makeType('', 'FrameReader'),
effectParams: makeType('', 'motionTrackEffectParams'),
Impr: makeType('None', 'none'),
Anch: makeType('', 'Pnt '),
'Fwd ': makeType('', 'Pnt '),
'Bwd ': makeType('', 'Pnt '),
FlrC: makeType('', 'Pnt '),
meshBoundaryPath: makeType('', 'pathClass'),
filterFX: makeType('', 'filterFXStyle'),
Fltr: makeType('', 'rigidTransform'),
FrgC: makeType('', 'RGBC'),
BckC: makeType('', 'RGBC'),
sdwM: makeType('Parameters', 'adaptCorrectTones'),
hglM: makeType('Parameters', 'adaptCorrectTones'),
customShape: makeType('', 'customShape'),
origFXRefPoint: nullType,
FXRefPoint: nullType,
ClMg: makeType('', 'ClMg'),
};
var fieldToArrayExtType = {
'Crv ': makeType('', 'CrPt'),
Clrs: makeType('', 'Clrt'),
Trns: makeType('', 'TrnS'),
keyDescriptorList: nullType,
solidFillMulti: makeType('', 'SoFi'),
gradientFillMulti: makeType('', 'GrFl'),
dropShadowMulti: makeType('', 'DrSh'),
innerShadowMulti: makeType('', 'IrSh'),
frameFXMulti: makeType('', 'FrFX'),
FrIn: nullType,
FSts: nullType,
LaSt: nullType,
sheetTimelineOptions: nullType,
trackList: makeType('', 'animationTrack'),
globalTrackList: makeType('', 'animationTrack'),
keyList: nullType,
audioClipGroupList: nullType,
audioClipList: nullType,
countObjectList: makeType('', 'countObject'),
countGroupList: makeType('', 'countGroup'),
slices: makeType('', 'slice'),
'Pts ': makeType('', 'Pthp'),
SbpL: makeType('', 'SbpL'),
pathComponents: makeType('', 'PaCm'),
filterFXList: makeType('', 'filterFX'),
puppetShapeList: makeType('', 'puppetShape'),
channelDenoise: makeType('', 'channelDenoiseParams'),
ShrP: makeType('', 'Pnt '),
layerSettings: nullType,
list: nullType,
Adjs: makeType('', 'CrvA'),
};
var typeToField = {
'TEXT': [
'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath',
],
'tdta': [
'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
'LqMe',
],
'long': [
'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'comp', 'compID', 'originalCompID',
'curvesPresetKind', 'mixerPresetKind', 'uOrder', 'vOrder', 'PgNm', 'totalPages', 'Crop',
'numerator', 'denominator', 'frameCount', 'Annt', 'keyOriginType', 'unitValueQuadVersion',
'keyOriginIndex', 'major', 'minor', 'fix', 'docDefaultNewArtboardBackgroundType', 'artboardBackgroundType',
'numModifyingFX', 'deformNumRows', 'deformNumCols', 'FrID', 'FrDl', 'FsID', 'LCnt', 'AFrm', 'AFSt',
'numBefore', 'numAfter', 'Spcn', 'minOpacity', 'maxOpacity', 'BlnM', 'sheetID', 'gblA', 'globalAltitude',
'descVersion', 'frameReaderType', 'LyrI', 'zoomOrigin', 'fontSize', 'Rds ', 'sliceID',
'topOutset', 'leftOutset', 'bottomOutset', 'rightOutset', 'filterID', 'meshQuality',
'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
],
'enum': [
'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
'bvlT', 'bvlS', 'bvlD', 'Md ', 'glwS', 'GrdF', 'GlwT', 'RplS', 'BlrM', 'SmBM',
'strokeStyleLineCapType', 'strokeStyleLineJoinType', 'strokeStyleLineAlignment',
'strokeStyleBlendMode', 'PntT', 'Styl', 'lookupType', 'LUTFormat', 'dataOrder',
'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
],
'bool': [
'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
'useShape', 'useTexture', 'uglg', 'antialiasGloss', 'useShape', 'Vsbl',
'useTexture', 'Algn', 'Rvrs', 'Dthr', 'Invr', 'VctC', 'ShTr', 'layerConceals',
'strokeEnabled', 'fillEnabled', 'strokeStyleScaleLock', 'strokeStyleStrokeAdjust',
'hardProof', 'MpBl', 'paperWhite', 'useLegacy', 'Auto', 'Lab ', 'useTint', 'keyShapeInvalidated',
'autoExpandEnabled', 'autoNestEnabled', 'autoPositionEnabled', 'shrinkwrapOnSaveEnabled',
'present', 'showInDialog', 'overprint', 'sheetDisclosed', 'lightsDisclosed', 'meshesDisclosed',
'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
'moreAccurate', 'GpuY', 'LIWy', 'Cnty',
],
'doub': [
'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3'
],
'UntF': [
'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
'Ckmt', 'Nose', 'Inpr', 'ShdN', 'strokeStyleLineWidth', 'strokeStyleLineDashOffset',
'strokeStyleOpacity', 'H ', 'Top ', 'Left', 'Btom', 'Rght', 'Rslt',
'topRight', 'topLeft', 'bottomLeft', 'bottomRight', 'ClNs', 'Shrp',
],
'VlLs': [
'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
'LaSt', 'Trnf', 'nonAffineTransform', 'keyDescriptorList', 'guideIndeces', 'gradientFillMulti',
'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList', 'ShrP',
'channelDenoise', 'Mtrx', 'layerSettings', 'list', 'compList', 'Adjs',
],
'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
'obj ': ['null', 'Chnl'],
'Pth ': ['DspF'],
};
var channels = [
'Rd ', 'Grn ', 'Bl ', 'Yllw', 'Ylw ', 'Cyn ', 'Mgnt', 'Blck', 'Gry ', 'Lmnc', 'A ', 'B ',
];
var fieldToArrayType = {
'Mnm ': 'long',
'Mxm ': 'long',
FrLs: 'long',
strokeStyleLineDashSet: 'UntF',
Trnf: 'doub',
nonAffineTransform: 'doub',
keyDescriptorList: 'Objc',
gradientFillMulti: 'Objc',
solidFillMulti: 'Objc',
frameFXMulti: 'Objc',
innerShadowMulti: 'Objc',
dropShadowMulti: 'Objc',
LaSt: 'Objc',
FrIn: 'Objc',
FSts: 'Objc',
FsFr: 'long',
blendOptions: 'Objc',
sheetTimelineOptions: 'Objc',
keyList: 'Objc',
warpValues: 'doub',
selectedPin: 'long',
'Pts ': 'Objc',
SbpL: 'Objc',
pathComponents: 'Objc',
pinOffsets: 'doub',
posFinalPins: 'doub',
pinVertexIndices: 'long',
PinP: 'doub',
PnRt: 'long',
PnOv: 'bool',
PnDp: 'doub',
filterFXList: 'Objc',
puppetShapeList: 'Objc',
ShrP: 'Objc',
channelDenoise: 'Objc',
Mtrx: 'long',
compList: 'long',
Chnl: 'enum',
};
var fieldToType = {};
for (var _i = 0, _a = Object.keys(typeToField); _i < _a.length; _i++) {
var type = _a[_i];
for (var _b = 0, _c = typeToField[type]; _b < _c.length; _b++) {
var field = _c[_b];
fieldToType[field] = type;
}
}
for (var _d = 0, _e = Object.keys(fieldToExtType); _d < _e.length; _d++) {
var field = _e[_d];
if (!fieldToType[field])
fieldToType[field] = 'Objc';
}
for (var _f = 0, _g = Object.keys(fieldToArrayExtType); _f < _g.length; _f++) {
var field = _g[_f];
fieldToArrayType[field] = 'Objc';
}
function getTypeByKey(key, value, root, parent) {
if (key === 'presetKind') {
return typeof value === 'string' ? 'enum' : 'long';
}
if (key === 'null' && root === 'slices') {
return 'TEXT';
}
else if (key === 'groupID') {
return root === 'slices' ? 'long' : 'TEXT';
}
else if (key === 'Sz ') {
return ('Wdth' in value) ? 'Objc' : (('units' in value) ? 'UntF' : 'doub');
}
else if (key === 'Type') {
return typeof value === 'string' ? 'enum' : 'long';
}
else if (key === 'AntA') {
return typeof value === 'string' ? 'enum' : 'bool';
}
else if ((key === 'Hrzn' || key === 'Vrtc') && (parent.Type === 'keyType.Pstn' || parent._classID === 'Ofst')) {
return 'long';
}
else if (key === 'Hrzn' || key === 'Vrtc' || key === 'Top ' || key === 'Left' || key === 'Btom' || key === 'Rght') {
if (root === 'slices')
return 'long';
return typeof value === 'number' ? 'doub' : 'UntF';
}
else if (key === 'Vrsn') {
return typeof value === 'number' ? 'long' : 'Objc';
}
else if (key === 'Rd ' || key === 'Grn ' || key === 'Bl ') {
return root === 'artd' ? 'long' : 'doub';
}
else if (key === 'Trnf') {
return Array.isArray(value) ? 'VlLs' : 'Objc';
}
else {
return fieldToType[key];
}
}
export function readAsciiStringOrClassId(reader) {
var length = readInt32(reader);
return readAsciiString(reader, length || 4);
}
function writeAsciiStringOrClassId(writer, value) {
if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list') {
// write classId
writeInt32(writer, 0);
writeSignature(writer, value);
}
else {
// write ascii string
writeInt32(writer, value.length);
for (var i = 0; i < value.length; i++) {
writeUint8(writer, value.charCodeAt(i));
}
}
}
export function readDescriptorStructure(reader, includeClass) {
var struct = readClassStructure(reader);
var object = includeClass ? { _name: struct.name, _classID: struct.classID } : {};
// console.log('>> ', struct);
var itemsCount = readUint32(reader);
for (var i = 0; i < itemsCount; i++) {
var key = readAsciiStringOrClassId(reader);
var type = readSignature(reader);
// console.log(`> '${key}' '${type}'`);
var data = readOSType(reader, type, includeClass);
// if (!getTypeByKey(key, data)) console.log(`> '${key}' '${type}'`, data);
object[key] = data;
}
return object;
}
export function writeDescriptorStructure(writer, name, classId, value, root) {
if (logErrors && !classId)
console.log('Missing classId for: ', name, classId, value);
// write class structure
writeUnicodeStringWithPadding(writer, name);
writeAsciiStringOrClassId(writer, classId);
var keys = Object.keys(value);
var keyCount = keys.length;
if ('_name' in value)
keyCount--;
if ('_classID' in value)
keyCount--;
writeUint32(writer, keyCount);
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (key === '_name' || key === '_classID')
continue;
var type = getTypeByKey(key, value[key], root, value);
var extType = fieldToExtType[key];
if (key === 'bounds' && root === 'text') {
extType = makeType('', 'bounds');
}
else if (key === 'origin') {
type = root === 'slices' ? 'enum' : 'Objc';
}
else if ((key === 'Cyn ' || key === 'Mgnt' || key === 'Ylw ' || key === 'Blck') && value._classID === 'CMYC') {
type = 'doub';
}
else if (/^PN[a-z][a-z]$/.test(key)) {
type = 'TEXT';
}
else if (/^PT[a-z][a-z]$/.test(key)) {
type = 'long';
}
else if (/^PF[a-z][a-z]$/.test(key)) {
type = 'doub';
}
else if ((key === 'Rds ' || key === 'Thsh') && typeof value[key] === 'number' && value._classID === 'SmrB') {
type = 'doub';
}
else if (key === 'ClSz' || key === 'Rds ' || key === 'Amnt') {
type = typeof value[key] === 'number' ? 'long' : 'UntF';
}
else if ((key === 'sdwM' || key === 'hglM') && typeof value[key] === 'string') {
type = 'enum';
}
else if (key === 'blur' && typeof value[key] === 'string') {
type = 'enum';
}
else if (key === 'Hght' && typeof value[key] === 'number' && value._classID === 'Embs') {
type = 'long';
}
else if (key === 'Angl' && typeof value[key] === 'number' && (value._classID === 'Embs' || value._classID === 'smartSharpen' || value._classID === 'Twrl' || value._classID === 'MtnB')) {
type = 'long';
}
else if (key === 'Angl' && typeof value[key] === 'number') {
type = 'doub'; // ???
}
else if (key === 'bounds' && root === 'slices') {
type = 'Objc';
extType = makeType('', 'Rct1');
}
else if (key === 'Scl ') {
if (typeof value[key] === 'object' && 'Hrzn' in value[key]) {
type = 'Objc';
extType = nullType;
}
else if (typeof value[key] === 'number') {
type = 'long';
}
else {
type = 'UntF';
}
}
else if (key === 'audioClipGroupList' && keys.length === 1) {
type = 'VlLs';
}
else if ((key === 'Strt' || key === 'Brgh') && 'H ' in value) {
type = 'doub';
}
else if (key === 'Wdth' && typeof value[key] === 'object') {
type = 'UntF';
}
else if (key === 'Ofst' && typeof value[key] === 'number') {
type = 'long';
}
else if (key === 'Strt' && typeof value[key] === 'object') {
type = 'Objc';
extType = nullType;
}
else if (channels.indexOf(key) !== -1) {
type = (classId === 'RGBC' && root !== 'artd') ? 'doub' : 'long';
}
else if (key === 'profile') {
type = classId === 'printOutput' ? 'TEXT' : 'tdta';
}
else if (key === 'strokeStyleContent') {
if (value[key]['Clr ']) {
extType = makeType('', 'solidColorLayer');
}
else if (value[key].Grad) {
extType = makeType('', 'gradientLayer');
}
else if (value[key].Ptrn) {
extType = makeType('', 'patternLayer');
}
else {
logErrors && console.log('Invalid strokeStyleContent value', value[key]);
}
}
else if (key === 'bounds' && root === 'quiltWarp') {
extType = makeType('', 'classFloatRect');
}
if (extType && extType.classID === 'RGBC') {
if ('H ' in value[key])
extType = { classID: 'HSBC', name: '' };
// TODO: other color spaces
}
writeAsciiStringOrClassId(writer, key);
writeSignature(writer, type || 'long');
writeOSType(writer, type || 'long', value[key], key, extType, root);
if (logErrors && !type)
console.log("Missing descriptor field type for: '".concat(key, "' in"), value);
}
}
function readOSType(reader, type, includeClass) {
switch (type) {
case 'obj ': // Reference
return readReferenceStructure(reader);
case 'Objc': // Descriptor
case 'GlbO': // GlobalObject same as Descriptor
return readDescriptorStructure(reader, includeClass);
case 'VlLs': { // List
var length_1 = readInt32(reader);
var items = [];
for (var i = 0; i < length_1; i++) {
var itemType = readSignature(reader);
// console.log(' >', itemType);
items.push(readOSType(reader, itemType, includeClass));
}
return items;
}
case 'doub': // Double
return readFloat64(reader);
case 'UntF': { // Unit double
var units = readSignature(reader);
var value = readFloat64(reader);
if (!unitsMap[units])
throw new Error("Invalid units: ".concat(units));
return { units: unitsMap[units], value: value };
}
case 'UnFl': { // Unit float
var units = readSignature(reader);
var value = readFloat32(reader);
if (!unitsMap[units])
throw new Error("Invalid units: ".concat(units));
return { units: unitsMap[units], value: value };
}
case 'TEXT': // String
return readUnicodeString(reader);
case 'enum': { // Enumerated
var enumType = readAsciiStringOrClassId(reader);
var value = readAsciiStringOrClassId(reader);
return "".concat(enumType, ".").concat(value);
}
case 'long': // Integer
return readInt32(reader);
case 'comp': { // Large Integer
var low = readUint32(reader);
var high = readUint32(reader);
return { low: low, high: high };
}
case 'bool': // Boolean
return !!readUint8(reader);
case 'type': // Class
case 'GlbC': // Class
return readClassStructure(reader);
case 'alis': { // Alias
var length_2 = readInt32(reader);
return readAsciiString(reader, length_2);
}
case 'tdta': { // Raw Data
var length_3 = readInt32(reader);
return readBytes(reader, length_3);
}
case 'ObAr': { // Object array
readInt32(reader); // version: 16
readUnicodeString(reader); // name: ''
readAsciiStringOrClassId(reader); // 'rationalPoint'
var length_4 = readInt32(reader);
var items = [];
for (var i = 0; i < length_4; i++) {
var type1 = readAsciiStringOrClassId(reader); // type Hrzn | Vrtc
readSignature(reader); // UnFl
readSignature(reader); // units ? '#Pxl'
var valuesCount = readInt32(reader);
var values = [];
for (var j = 0; j < valuesCount; j++) {
values.push(readFloat64(reader));
}
items.push({ type: type1, values: values });
}
return items;
}
case 'Pth ': { // File path
/*const length =*/ readInt32(reader); // total size of all fields below
var sig = readSignature(reader);
/*const pathSize =*/ readInt32LE(reader); // the same as length
var charsCount = readInt32LE(reader);
var path = readUnicodeStringWithLengthLE(reader, charsCount);
return { sig: sig, path: path };
}
default:
throw new Error("Invalid TySh descriptor OSType: ".concat(type, " at ").concat(reader.offset.toString(16)));
}
}
var ObArTypes = {
meshPoints: 'rationalPoint',
quiltSliceX: 'UntF',
quiltSliceY: 'UntF',
};
function writeOSType(writer, type, value, key, extType, root) {
switch (type) {
case 'obj ': // Reference
writeReferenceStructure(writer, key, value);
break;
case 'Objc': // Descriptor
case 'GlbO': { // GlobalObject same as Descriptor
if (typeof value !== 'object')
throw new Error("Invalid struct value: ".concat(JSON.stringify(value), ", key: ").concat(key));
if (!extType)
throw new Error("Missing ext type for: '".concat(key, "' (").concat(JSON.stringify(value), ")"));
var name_1 = value._name || extType.name;
var classID = value._classID || extType.classID;
writeDescriptorStructure(writer, name_1, classID, value, root);
break;
}
case 'VlLs': // List
if (!Array.isArray(value))
throw new Error("Invalid list value: ".concat(JSON.stringify(value), ", key: ").concat(key));
writeInt32(writer, value.length);
for (var i = 0; i < value.length; i++) {
var type_1 = fieldToArrayType[key];
writeSignature(writer, type_1 || 'long');
writeOSType(writer, type_1 || 'long', value[i], "".concat(key, "[]"), fieldToArrayExtType[key], root);
if (logErrors && !type_1)
console.log("Missing descriptor array type for: '".concat(key, "' in"), value);
}
break;
case 'doub': // Double
if (typeof value !== 'number')
throw new Error("Invalid number value: ".concat(JSON.stringify(value), ", key: ").concat(key));
writeFloat64(writer, value);
break;
case 'UntF': // Unit double
if (!unitsMapRev[value.units])
throw new Error("Invalid units: ".concat(value.units, " in ").concat(key));
writeSignature(writer, unitsMapRev[value.units]);
writeFloat64(writer, value.value);
break;
case 'UnFl': // Unit float
if (!unitsMapRev[value.units])
throw new Error("Invalid units: ".concat(value.units, " in ").concat(key));
writeSignature(writer, unitsMapRev[value.units]);
writeFloat32(writer, value.value);
break;
case 'TEXT': // String
writeUnicodeStringWithPadding(writer, value);
break;
case 'enum': { // Enumerated
if (typeof value !== 'string')
throw new Error("Invalid enum value: ".concat(JSON.stringify(value), ", key: ").concat(key));
var _a = value.split('.'), _type = _a[0], val = _a[1];
writeAsciiStringOrClassId(writer, _type);
writeAsciiStringOrClassId(writer, val);
break;
}
case 'long': // Integer
if (typeof value !== 'number')
throw new Error("Invalid integer value: ".concat(JSON.stringify(value), ", key: ").concat(key));
writeInt32(writer, value);
break;
// case 'comp': // Large Integer
// writeLargeInteger(reader);
case 'bool': // Boolean
if (typeof value !== 'boolean')
throw new Error("Invalid boolean value: ".concat(JSON.stringify(value), ", key: ").concat(key));
writeUint8(writer, value ? 1 : 0);
break;
// case 'type': // Class
// case 'GlbC': // Class
// writeClassStructure(reader);
// case 'alis': // Alias
// writeAliasStructure(reader);
case 'tdta': // Raw Data
writeInt32(writer, value.byteLength);
writeBytes(writer, value);
break;
case 'ObAr': { // Object array
writeInt32(writer, 16); // version
writeUnicodeStringWithPadding(writer, ''); // name
var type_2 = ObArTypes[key];
if (!type_2)
throw new Error("Not implemented ObArType for: ".concat(key));
writeAsciiStringOrClassId(writer, type_2);
writeInt32(writer, value.length);
for (var i = 0; i < value.length; i++) {
writeAsciiStringOrClassId(writer, value[i].type); // Hrzn | Vrtc
writeSignature(writer, 'UnFl');
writeSignature(writer, '#Pxl');
writeInt32(writer, value[i].values.length);
for (var j = 0; j < value[i].values.length; j++) {
writeFloat64(writer, value[i].values[j]);
}
}
break;
}
case 'Pth ': { // File path
var length_5 = 4 + 4 + 4 + value.path.length * 2;
writeInt32(writer, length_5);
writeSignature(writer, value.sig);
writeInt32LE(writer, length_5);
writeInt32LE(writer, value.path.length);
writeUnicodeStringWithoutLengthLE(writer, value.path);
break;
}
default:
throw new Error("Not implemented descriptor OSType: ".concat(type));
}
}
function readReferenceStructure(reader) {
var itemsCount = readInt32(reader);
var items = [];
for (var i = 0; i < itemsCount; i++) {
var type = readSignature(reader);
switch (type) {
case 'prop': { // Property
readClassStructure(reader);
var keyID = readAsciiStringOrClassId(reader);
items.push(keyID);
break;
}
case 'Clss': // Class
items.push(readClassStructure(reader));
break;
case 'Enmr': { // Enumerated Reference
readClassStructure(reader);
var typeID = readAsciiStringOrClassId(reader);
var value = readAsciiStringOrClassId(reader);
items.push("".concat(typeID, ".").concat(value));
break;
}
case 'rele': { // Offset
// const { name, classID } =
readClassStructure(reader);
items.push(readUint32(reader));
break;
}
case 'Idnt': // Identifier
items.push(readInt32(reader));
break;
case 'indx': // Index
items.push(readInt32(reader));
break;
case 'name': { // Name
readClassStructure(reader);
items.push(readUnicodeString(reader));
break;
}
default:
throw new Error("Invalid descriptor reference type: ".concat(type));
}
}
return items;
}
function writeReferenceStructure(writer, _key, items) {
writeInt32(writer, items.length);
for (var i = 0; i < items.length; i++) {
var value = items[i];
var type = 'unknown';
if (typeof value === 'string') {
if (/^[a-z ]+\.[a-z ]+$/i.test(value)) {
type = 'Enmr';
}
else {
type = 'name';
}
}
writeSignature(writer, type);
switch (type) {
// case 'prop': // Property
// case 'Clss': // Class
case 'Enmr': { // Enumerated Reference
var _a = value.split('.'), typeID = _a[0], enumValue = _a[1];
writeClassStructure(writer, '\0', typeID);
writeAsciiStringOrClassId(writer, typeID);
writeAsciiStringOrClassId(writer, enumValue);
break;
}
// case 'rele': // Offset
// case 'Idnt': // Identifier
// case 'indx': // Index
case 'name': { // Name
writeClassStructure(writer, '\0', 'Lyr ');
writeUnicodeString(writer, value + '\0');
break;
}
default:
throw new Error("Invalid descriptor reference type: ".concat(type));
}
}
return items;
}
function readClassStructure(reader) {
var name = readUnicodeString(reader);
var classID = readAsciiStringOrClassId(reader);
return { name: name, classID: classID };
}
function writeClassStructure(writer, name, classID) {
writeUnicodeString(writer, name);
writeAsciiStringOrClassId(writer, classID);
}
export function readVersionAndDescriptor(reader, includeClass) {
if (includeClass === void 0) { includeClass = false; }
var version = readUint32(reader);
if (version !== 16)
throw new Error("Invalid descriptor version: ".concat(version));
var desc = readDescriptorStructure(reader, includeClass);
// console.log(require('util').inspect(desc, false, 99, true));
return desc;
}
export function writeVersionAndDescriptor(writer, name, classID, descriptor, root) {
if (root === void 0) { root = ''; }
writeUint32(writer, 16); // version
writeDescriptorStructure(writer, name, classID, descriptor, root);
}
export function horzVrtcToXY(hv) {
return { x: hv.Hrzn, y: hv.Vrtc };
}
export function xyToHorzVrtc(xy) {
return { Hrzn: xy.x, Vrtc: xy.y };
}
export function descBoundsToBounds(desc) {
return {
top: parseUnits(desc['Top ']),
left: parseUnits(desc.Left),
right: parseUnits(desc.Rght),
bottom: parseUnits(desc.Btom),
};
}
export function boundsToDescBounds(bounds) {
var _a;
return _a = {
Left: unitsValue(bounds.left, 'bounds.left')
},
_a['Top '] = unitsValue(bounds.top, 'bounds.top'),
_a.Rght = unitsValue(bounds.right, 'bounds.right'),
_a.Btom = unitsValue(bounds.bottom, 'bounds.bottom'),
_a;
}
function parseFxObject(fx) {
var stroke = {
enabled: !!fx.enab,
position: FStl.decode(fx.Styl),
fillType: FrFl.decode(fx.PntT),
blendMode: BlnM.decode(fx['Md ']),
opacity: parsePercent(fx.Opct),
size: parseUnits(fx['Sz ']),
};
if (fx.present !== undefined)
stroke.present = fx.present;
if (fx.showInDialog !== undefined)
stroke.showInDialog = fx.showInDialog;
if (fx.overprint !== undefined)
stroke.overprint = fx.overprint;
if (fx['Clr '])
stroke.color = parseColor(fx['Clr ']);
if (fx.Grad)
stroke.gradient = parseGradientContent(fx);
if (fx.Ptrn)
stroke.pattern = parsePatternContent(fx);
return stroke;
}
function serializeFxObject(stroke) {
var FrFX = {};
FrFX.enab = !!stroke.enabled;
if (stroke.present !== undefined)
FrFX.present = !!stroke.present;
if (stroke.showInDialog !== undefined)
FrFX.showInDialog = !!stroke.showInDialog;
FrFX.Styl = FStl.encode(stroke.position);
FrFX.PntT = FrFl.encode(stroke.fillType);
FrFX['Md '] = BlnM.encode(stroke.blendMode);
FrFX.Opct = unitsPercent(stroke.opacity);
FrFX['Sz '] = unitsValue(stroke.size, 'size');
if (stroke.color)
FrFX['Clr '] = serializeColor(stroke.color);
if (stroke.gradient)
FrFX = __assign(__assign({}, FrFX), serializeGradientContent(stroke.gradient));
if (stroke.pattern)
FrFX = __assign(__assign({}, FrFX), serializePatternContent(stroke.pattern));
if (stroke.overprint !== undefined)
FrFX.overprint = !!stroke.overprint;
return FrFX;
}
export function serializeEffects(e, log, multi) {
var _a, _b, _c;
var info = multi ? {
'Scl ': unitsPercentF((_a = e.scale) !== null && _a !== void 0 ? _a : 1),
masterFXSwitch: !e.disabled,
} : {
masterFXSwitch: !e.disabled,
'Scl ': unitsPercentF((_b = e.scale) !== null && _b !== void 0 ? _b : 1),
};
var arrayKeys = ['dropShadow', 'innerShadow', 'solidFill', 'gradientOverlay', 'stroke'];
for (var _i = 0, arrayKeys_1 = arrayKeys; _i < arrayKeys_1.length; _i++) {
var key = arrayKeys_1[_i];
if (e[key] && !Array.isArray(e[key]))
throw new Error("".concat(key, " should be an array"));
}
var useMulti = function (arr) { return !!arr && arr.length > 1 && multi; };
var useSingle = function (arr) { return !!arr && arr.length >= 1 && (!multi || arr.length === 1); };
if (useSingle(e.dropShadow))
info.DrSh = serializeEffectObject(e.dropShadow[0], 'dropShadow', log);
if (useMulti(e.dropShadow))
info.dropShadowMulti = e.dropShadow.map(function (i) { return serializeEffectObject(i, 'dropShadow', log); });
if (useSingle(e.innerShadow))
info.IrSh = serializeEffectObject(e.innerShadow[0], 'innerShadow', log);
if (useMulti(e.innerShadow))
info.innerShadowMulti = e.innerShadow.map(function (i) { return serializeEffectObject(i, 'innerShadow', log); });
if (e.outerGlow)
info.OrGl = serializeEffectObject(e.outerGlow, 'outerGlow', log);
if (useMulti(e.solidFill))
info.solidFillMulti = e.solidFill.map(function (i) { return serializeEffectObject(i, 'solidFill', log); });
if (useMulti(e.gradientOverlay))
info.gradientFillMulti = e.gradientOverlay.map(function (i) { return serializeEffectObject(i, 'gradientOverlay', log); });
if (useMulti(e.stroke))
info.frameFXMulti = e.stroke.map(function (i) { return serializeFxObject(i); });
if (e.innerGlow)
info.IrGl = serializeEffectObject(e.innerGlow, 'innerGlow', log);
if (e.bevel)
info.ebbl = serializeEffectObject(e.bevel, 'bevel', log);
if (useSingle(e.solidFill))
info.SoFi = serializeEffectObject(e.solidFill[0], 'solidFill', log);
if (e.patternOverlay)
info.patternFill = serializeEffectObject(e.patternOverlay, 'patternOverlay', log);
if (useSingle(e.gradientOverlay))
info.GrFl = serializeEffectObject(e.gradientOverlay[0], 'gradientOverlay', log);
if (e.satin)
info.ChFX = serializeEffectObject(e.satin, 'satin', log);
if (useSingle(e.stroke))
info.FrFX = serializeFxObject((_c = e.stroke) === null || _c === void 0 ? void 0 : _c[0]);
if (multi) {
info.numModifyingFX = 0;
for (var _d = 0, _e = Object.keys(e); _d < _e.length; _d++) {
var key = _e[_d];
var value = e[key];
if (Array.isArray(value)) {
for (var _f = 0, value_1 = value; _f < value_1.length; _f++) {
var effect = value_1[_f];
if (effect.enabled)
info.numModifyingFX++;
}
}
else if (value.enabled) {
info.numModifyingFX++;
}
}
}
return info;
}
export function parseEffects(info, log) {
var effects = {};
var masterFXSwitch = info.masterFXSwitch, DrSh = info.DrSh, dropShadowMulti = info.dropShadowMulti, IrSh = info.IrSh, innerShadowMulti = info.innerShadowMulti, OrGl = info.OrGl, IrGl = info.IrGl, ebbl = info.ebbl, SoFi = info.SoFi, solidFillMulti = info.solidFillMulti, patternFill = info.patternFill, GrFl = info.GrFl, gradientFillMulti = info.gradientFillMulti, ChFX = info.ChFX, FrFX = info.FrFX, frameFXMulti = info.frameFXMulti, numModifyingFX = info.numModifyingFX, rest = __rest(info, ["masterFXSwitch", "DrSh", "dropShadowMulti", "IrSh", "innerShadowMulti", "OrGl", "IrGl", "ebbl", "SoFi", "solidFillMulti", "patternFill", "GrFl", "gradientFillMulti", "ChFX", "FrFX", "frameFXMulti", "numModifyingFX"]);
if (!masterFXSwitch)
effects.disabled = true;
if (info['Scl '])
effects.scale = parsePercent(info['Scl ']);
if (DrSh)
effects.dropShadow = [parseEffectObject(DrSh, log)];
if (dropShadowMulti)
effects.dropShadow = dropShadowMulti.map(function (i) { return parseEffectObject(i, log); });
if (IrSh)
effects.innerShadow = [parseEffectObject(IrSh, log)];
if (innerShadowMulti)
effects.innerShadow = innerShadowMulti.map(function (i) { return parseEffectObject(i, log); });
if (OrGl)
effects.outerGlow = parseEffectObject(OrGl, log);
if (IrGl)
effects.innerGlow = parseEffectObject(IrGl, log);
if (ebbl)
effects.bevel = parseEffectObject(ebbl, log);
if (SoFi)
effects.solidFill = [parseEffectObject(SoFi, log)];
if (solidFillMulti)
effects.solidFill = solidFillMulti.map(function (i) { return parseEffectObject(i, log); });
if (patternFill)
effects.patternOverlay = parseEffectObject(patternFill, log);
if (GrFl)
effects.gradientOverlay = [parseEffectObject(GrFl, log)];
if (gradientFillMulti)
effects.gradientOverlay = gradientFillMulti.map(function (i) { return parseEffectObject(i, log); });
if (ChFX)
effects.satin = parseEffectObject(ChFX, log);
if (FrFX)
effects.stroke = [parseFxObject(FrFX)];
if (frameFXMulti)
effects.stroke = frameFXMulti.map(function (i) { return parseFxObject(i); });
if (log && Object.keys(rest).length > 1)
console.log('Unhandled effect keys:', rest);
return effects;
}
function parseKeyList(keyList, logMissingFeatures) {
var keys = [];
for (var j = 0; j < keyList.length; j++) {
var key = keyList[j];
var _a = key.time, denominator = _a.denominator, numerator = _a.numerator, selected = key.selected, animKey = key.animKey;
var time = { numerator: numerator, denominator: denominator };
var interpolation = animInterpStyleEnum.decode(key.animInterpStyle);
switch (animKey.Type) {
case 'keyType.Opct':
keys.push({ interpolation: interpolation, time: time, selected: selected, type: 'opacity', value: parsePercent(animKey.Opct) });
break;
case 'keyType.Pstn':
keys.push({ interpolation: interpolation, time: time, selected: selected, type: 'position', x: animKey.Hrzn, y: animKey.Vrtc });
break;
case 'keyType.Trnf':
keys.push({
interpolation: interpolation,
time: time,
selected: selected,
type: 'transform',
scale: horzVrtcToXY(animKey['Scl ']), skew: horzVrtcToXY(animKey.Skew), rotation: animKey.rotation, translation: horzVrtcToXY(animKey.translation)
});
break;
case 'keyType.sheetStyle': {
var key_1 = { interpolation: interpolation, time: time, selected: selected, type: 'style' };
if (animKey.sheetStyle.Lefx)
key_1.style = parseEffects(animKey.sheetStyle.Lefx, logMissingFeatures);
keys.push(key_1);
break;
}
case 'keyType.globalLighting': {
keys.push({
interpolation: interpolation,
time: time,
selected: selected,
type: 'globalLighting',
globalAngle: animKey.gblA, globalAltitude: animKey.globalAltitude
});
break;
}
default: throw new Error("Unsupported keyType value");
}
}
return keys;
}
function serializeKeyList(keys) {
var keyList = [];
for (var j = 0; j < keys.length; j++) {
var key = keys[j];
var time = key.time, _a = key.selected, selected = _a === void 0 ? false : _a, interpolation = key.interpolation;
var animInterpStyle = animInterpStyleEnum.encode(interpolation);
var animKey = void 0;
switch (key.type) {
case 'opacity':
animKey = { Type: 'keyType.Opct', Opct: unitsPercent(key.value) };
break;
case 'position':
animKey = { Type: 'keyType.Pstn', Hrzn: key.x, Vrtc: key.y };
break;
case 'transform':
animKey = { Type: 'keyType.Trnf', 'Scl ': xyToHorzVrtc(key.scale), Skew: xyToHorzVrtc(key.skew), rotation: key.rotation, translation: xyToHorzVrtc(key.translation) };
break;
case 'style':
animKey = { Type: 'keyType.sheetStyle', sheetStyle: { Vrsn: 1, blendOptions: {} } };
if (key.style)
animKey.sheetStyle = { Vrsn: 1, Lefx: serializeEffects(key.style, false, false), blendOptions: {} };
break;
case 'globalLighting': {
animKey = { Type: 'keyType.globalLighting', gblA: key.globalAngle, globalAltitude: key.globalAltitude };
break;
}
default: throw new Error("Unsupported keyType value");
}
keyList.push({ Vrsn: 1, animInterpStyle: animInterpStyle, time: time, animKey: animKey, selected: selected });
}
return keyList;
}
export function parseTrackList(trackList, logMissingFeatures) {
var tracks = [];
for (var i = 0; i < trackList.length; i++) {
var tr = trackList[i];
var track = {
type: stdTrackID.decode(tr.trackID),
enabled: tr.enab,
keys: parseKeyList(tr.keyList, logMissingFeatures),
};
if (tr.effectParams) {
track.effectParams = {
fillCanvas: tr.effectParams.fillCanvas,
zoomOrigin: tr.effectParams.zoomOrigin,
keys: parseKeyList(tr.effectParams.keyList, logMissingFeatures),
};
}
tracks.push(track);
}
return tracks;
}
export function serializeTrackList(tracks) {
var trackList = [];
for (var i = 0; i < tracks.length; i++) {
var t = tracks[i];
trackList.push(__assign(__assign({ trackID: stdTrackID.encode(t.type), Vrsn: 1, enab: !!t.enabled, Effc: !!t.effectParams }, (t.effectParams ? {
effectParams: {
keyList: serializeKeyList(t.keys),
fillCanvas: t.effectParams.fillCanvas,
zoomOrigin: t.effectParams.zoomOrigin,
}
} : {})), { keyList: serializeKeyList(t.keys) }));
}
return trackList;
}
function parseEffectObject(obj, reportErrors) {
var result = {};
for (var _i = 0, _a = Object.keys(obj); _i < _a.length; _i++) {
var key = _a[_i];
var val = obj[key];
switch (key) {
case 'enab':
result.enabled = !!val;
break;
case 'uglg':
result.useGlobalLight = !!val;
break;
case 'AntA':
result.antialiased = !!val;
break;
case 'Algn':
result.align = !!val;
break;
case 'Dthr':
result.dither = !!val;
break;
case 'Invr':
result.invert = !!val;
break;
case 'Rvrs':
result.reverse = !!val;
break;
case 'Clr ':
result.color = parseColor(val);
break;
case 'hglC':
result.highlightColor = parseColor(val);
break;
case 'sdwC':
result.shadowColor = parseColor(val);
break;
case 'Styl':
result.position = FStl.decode(val);
break;
case 'Md ':
result.blendMode = BlnM.decode(val);
break;
case 'hglM':
result.highlightBlendMode = BlnM.decode(val);
break;
case 'sdwM':
result.shadowBlendMode = BlnM.decode(val);
break;
case 'bvlS':
result.style = BESl.decode(val);
break;
case 'bvlD':
result.direction = BESs.decode(val);
break;
case 'bvlT':
result.technique = bvlT.decode(val);
break;
case 'GlwT':
result.technique = BETE.decode(val);
break;
case 'glwS':
result.source = IGSr.decode(val);
break;
case 'Type':
result.type = GrdT.decode(val);
break;
case 'gs99':
result.interpolationMethod = gradientInterpolationMethodType.decode(val);