ag-psd
Version:
Library for reading and writing PSD files
918 lines (917 loc) • 792 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.agPsd = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readAbr = void 0;
var descriptor_1 = require("./descriptor");
var psdReader_1 = require("./psdReader");
var dynamicsControl = ['off', 'fade', 'pen pressure', 'pen tilt', 'stylus wheel', 'initial direction', 'direction', 'initial rotation', 'rotation'];
var toBrushType = {
_: 'brush',
MixB: 'mixer brush',
SmTl: 'smudge brush',
// PbTl
// ErTl
};
function parseDynamics(desc) {
return {
control: dynamicsControl[desc.bVTy],
steps: desc.fStp,
jitter: (0, descriptor_1.parsePercent)(desc.jitter),
minimum: (0, descriptor_1.parsePercent)(desc['Mnm ']),
};
}
function parseBrushShape(desc) {
var shape = {
size: (0, descriptor_1.parseUnitsToNumber)(desc.Dmtr, 'Pixels'),
angle: (0, descriptor_1.parseAngle)(desc.Angl),
roundness: (0, descriptor_1.parsePercent)(desc.Rndn),
spacingOn: desc.Intr,
spacing: (0, descriptor_1.parsePercent)(desc.Spcn),
flipX: desc.flipX,
flipY: desc.flipY,
};
if (desc['Nm '])
shape.name = desc['Nm '];
if (desc.Hrdn)
shape.hardness = (0, descriptor_1.parsePercent)(desc.Hrdn);
if (desc.sampledData)
shape.sampledData = desc.sampledData;
return shape;
}
function readAbr(buffer, options) {
var _a, _b, _c, _d;
if (options === void 0) { options = {}; }
var reader = (0, psdReader_1.createReader)(buffer.buffer, buffer.byteOffset, buffer.byteLength);
var version = (0, psdReader_1.readInt16)(reader);
var samples = [];
var brushes = [];
var patterns = [];
if (version === 1 || version === 2) {
throw new Error("Unsupported ABR version (".concat(version, ")")); // TODO: ...
}
else if (version === 6 || version === 7 || version === 9 || version === 10) {
var minorVersion = (0, psdReader_1.readInt16)(reader);
if (minorVersion !== 1 && minorVersion !== 2)
throw new Error('Unsupported ABR minor version');
while (reader.offset < reader.view.byteLength) {
(0, psdReader_1.checkSignature)(reader, '8BIM');
var type = (0, psdReader_1.readSignature)(reader);
var size = (0, psdReader_1.readUint32)(reader);
var end = reader.offset + size;
switch (type) {
case 'samp': {
while (reader.offset < end) {
var brushLength = (0, psdReader_1.readUint32)(reader);
while (brushLength & 3)
brushLength++; // pad to 4 byte alignment
var brushEnd = reader.offset + brushLength;
var id = (0, psdReader_1.readPascalString)(reader, 1);
// v1 - Skip the Int16 bounds rectangle and the unknown Int16.
// v2 - Skip the unknown bytes.
(0, psdReader_1.skipBytes)(reader, minorVersion === 1 ? 10 : 264);
var y = (0, psdReader_1.readInt32)(reader);
var x = (0, psdReader_1.readInt32)(reader);
var h = (0, psdReader_1.readInt32)(reader) - y;
var w = (0, psdReader_1.readInt32)(reader) - x;
if (w <= 0 || h <= 0)
throw new Error('Invalid bounds');
var bithDepth = (0, psdReader_1.readInt16)(reader);
var compression = (0, psdReader_1.readUint8)(reader); // 0 - raw, 1 - RLE
var alpha = new Uint8Array(w * h);
if (bithDepth === 8) {
if (compression === 0) {
alpha.set((0, psdReader_1.readBytes)(reader, alpha.byteLength));
}
else if (compression === 1) {
(0, psdReader_1.readDataRLE)(reader, { width: w, height: h, data: alpha }, w, h, bithDepth, 1, [0], false);
}
else {
throw new Error('Invalid compression');
}
}
else if (bithDepth === 16) {
if (compression === 0) {
for (var i = 0; i < alpha.byteLength; i++) {
alpha[i] = (0, psdReader_1.readUint16)(reader) >> 8; // convert to 8bit values
}
}
else if (compression === 1) {
throw new Error('not implemented (16bit RLE)'); // TODO: ...
}
else {
throw new Error('Invalid compression');
}
}
else {
throw new Error('Invalid depth');
}
samples.push({ id: id, bounds: { x: x, y: y, w: w, h: h }, alpha: alpha });
reader.offset = brushEnd;
}
break;
}
case 'desc': {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader, true);
// console.log(require('util').inspect(desc, false, 99, true));
for (var _i = 0, _e = desc.Brsh; _i < _e.length; _i++) {
var brush = _e[_i];
var b = {
name: brush['Nm '],
shape: parseBrushShape(brush.Brsh),
spacing: (0, descriptor_1.parsePercent)(brush.Spcn),
// TODO: brushGroup ???
wetEdges: brush.Wtdg,
noise: brush.Nose,
// TODO: TxtC ??? smoothing / build-up ?
// TODO: 'Rpt ' ???
useBrushSize: brush.useBrushSize, // ???
};
if (brush.interpretation != null)
b.interpretation = brush.interpretation;
if (brush.protectTexture != null)
b.protectTexture = brush.protectTexture;
if (brush.useTipDynamics) {
b.shapeDynamics = {
tiltScale: (0, descriptor_1.parsePercent)(brush.tiltScale),
sizeDynamics: parseDynamics(brush.szVr),
angleDynamics: parseDynamics(brush.angleDynamics),
roundnessDynamics: parseDynamics(brush.roundnessDynamics),
flipX: brush.flipX,
flipY: brush.flipY,
brushProjection: brush.brushProjection,
minimumDiameter: (0, descriptor_1.parsePercent)(brush.minimumDiameter),
minimumRoundness: (0, descriptor_1.parsePercent)(brush.minimumRoundness),
};
}
if (brush.useScatter) {
b.scatter = {
count: brush['Cnt '],
bothAxes: brush.bothAxes,
countDynamics: parseDynamics(brush.countDynamics),
scatterDynamics: parseDynamics(brush.scatterDynamics),
};
}
if (brush.useTexture && brush.Txtr) {
b.texture = {
id: brush.Txtr.Idnt,
name: brush.Txtr['Nm '],
blendMode: descriptor_1.BlnM.decode(brush.textureBlendMode),
depth: (0, descriptor_1.parsePercent)(brush.textureDepth),
depthMinimum: (0, descriptor_1.parsePercent)(brush.minimumDepth),
depthDynamics: parseDynamics(brush.textureDepthDynamics),
scale: (0, descriptor_1.parsePercent)(brush.textureScale),
invert: brush.InvT,
brightness: brush.textureBrightness,
contrast: brush.textureContrast,
};
}
var db = brush.dualBrush;
if (db && db.useDualBrush) {
b.dualBrush = {
flip: db.Flip,
shape: parseBrushShape(db.Brsh),
blendMode: descriptor_1.BlnM.decode(db.BlnM),
useScatter: db.useScatter,
spacing: (0, descriptor_1.parsePercent)(db.Spcn),
count: db['Cnt '],
bothAxes: db.bothAxes,
countDynamics: parseDynamics(db.countDynamics),
scatterDynamics: parseDynamics(db.scatterDynamics),
};
}
if (brush.useColorDynamics) {
b.colorDynamics = {
foregroundBackground: parseDynamics(brush.clVr),
hue: (0, descriptor_1.parsePercent)(brush['H ']),
saturation: (0, descriptor_1.parsePercent)(brush.Strt),
brightness: (0, descriptor_1.parsePercent)(brush.Brgh),
purity: (0, descriptor_1.parsePercent)(brush.purity),
perTip: brush.colorDynamicsPerTip,
};
}
if (brush.usePaintDynamics) {
b.transfer = {
flowDynamics: parseDynamics(brush.prVr),
opacityDynamics: parseDynamics(brush.opVr),
wetnessDynamics: parseDynamics(brush.wtVr),
mixDynamics: parseDynamics(brush.mxVr),
};
}
if (brush.useBrushPose) {
b.brushPose = {
overrideAngle: brush.overridePoseAngle,
overrideTiltX: brush.overridePoseTiltX,
overrideTiltY: brush.overridePoseTiltY,
overridePressure: brush.overridePosePressure,
pressure: (0, descriptor_1.parsePercent)(brush.brushPosePressure),
tiltX: brush.brushPoseTiltX,
tiltY: brush.brushPoseTiltY,
angle: brush.brushPoseAngle,
};
}
var to = brush.toolOptions;
if (to) {
b.toolOptions = {
type: toBrushType[to._classID] || 'brush',
brushPreset: to.brushPreset,
flow: (_a = to.flow) !== null && _a !== void 0 ? _a : 100,
smooth: (_b = to.Smoo) !== null && _b !== void 0 ? _b : 0,
mode: descriptor_1.BlnM.decode(to['Md '] || 'BlnM.Nrml'),
opacity: (_c = to.Opct) !== null && _c !== void 0 ? _c : 100,
smoothing: !!to.smoothing,
smoothingValue: to.smoothingValue || 0,
smoothingRadiusMode: !!to.smoothingRadiusMode,
smoothingCatchup: !!to.smoothingCatchup,
smoothingCatchupAtEnd: !!to.smoothingCatchupAtEnd,
smoothingZoomCompensation: !!to.smoothingZoomCompensation,
pressureSmoothing: !!to.pressureSmoothing,
usePressureOverridesSize: !!to.usePressureOverridesSize,
usePressureOverridesOpacity: !!to.usePressureOverridesOpacity,
useLegacy: !!to.useLegacy,
};
if (to.prVr)
b.toolOptions.flowDynamics = parseDynamics(to.prVr);
if (to.opVr)
b.toolOptions.opacityDynamics = parseDynamics(to.opVr);
if (to.szVr)
b.toolOptions.sizeDynamics = parseDynamics(to.szVr);
if ('wetness' in to)
b.toolOptions.wetness = to.wetness;
if ('dryness' in to)
b.toolOptions.dryness = to.dryness;
if ('mix' in to)
b.toolOptions.mix = to.mix;
if ('autoFill' in to)
b.toolOptions.autoFill = to.autoFill;
if ('autoClean' in to)
b.toolOptions.autoClean = to.autoClean;
if ('loadSolidColorOnly' in to)
b.toolOptions.loadSolidColorOnly = to.loadSolidColorOnly;
if ('sampleAllLayers' in to)
b.toolOptions.sampleAllLayers = to.sampleAllLayers;
if ('SmdF' in to)
b.toolOptions.smudgeFingerPainting = to.SmdF;
if ('SmdS' in to)
b.toolOptions.smudgeSampleAllLayers = to.SmdS;
if ('Prs ' in to)
b.toolOptions.strength = to['Prs '];
if ('SmdF' in to)
b.toolOptions.smudgeFingerPainting = to.SmdF;
if ('SmdS' in to)
b.toolOptions.smudgeSampleAllLayers = to.SmdS;
}
brushes.push(b);
}
break;
}
case 'patt': {
if (reader.offset < end) { // TODO: check multiple patterns
patterns.push((0, psdReader_1.readPattern)(reader));
reader.offset = end;
}
break;
}
case 'phry': {
// TODO: what is this ?
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
if (options.logMissingFeatures) {
if ((_d = desc.hierarchy) === null || _d === void 0 ? void 0 : _d.length) {
console.log('unhandled phry section', desc);
}
}
break;
}
default:
throw new Error("Invalid brush type: ".concat(type));
}
// align to 4 bytes
while (size % 4) {
reader.offset++;
size++;
}
}
}
else {
throw new Error("Unsupported ABR version (".concat(version, ")"));
}
return { samples: samples, patterns: patterns, brushes: brushes };
}
exports.readAbr = readAbr;
},{"./descriptor":4,"./psdReader":12}],2:[function(require,module,exports){
"use strict";
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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasMultiEffects = exports.readVectorMask = exports.booleanOperations = exports.readBezierKnot = exports.infoHandlersMap = exports.infoHandlers = void 0;
var base64_js_1 = require("base64-js");
var effectsHelpers_1 = require("./effectsHelpers");
var helpers_1 = require("./helpers");
var psdReader_1 = require("./psdReader");
var psdWriter_1 = require("./psdWriter");
var descriptor_1 = require("./descriptor");
var engineData_1 = require("./engineData");
var text_1 = require("./text");
var engineData2_1 = require("./engineData2");
var fromAtoZ = 'abcdefghijklmnopqrstuvwxyz';
exports.infoHandlers = [];
exports.infoHandlersMap = {};
function addHandler(key, has, read, write) {
var handler = { key: key, has: has, read: read, write: write };
exports.infoHandlers.push(handler);
exports.infoHandlersMap[handler.key] = handler;
}
function addHandlerAlias(key, target) {
exports.infoHandlersMap[key] = exports.infoHandlersMap[target];
}
function hasKey(key) {
return function (target) { return target[key] !== undefined; };
}
function readLength64(reader) {
if ((0, psdReader_1.readUint32)(reader))
throw new Error("Resource size above 4 GB limit at ".concat(reader.offset.toString(16)));
return (0, psdReader_1.readUint32)(reader);
}
function writeLength64(writer, length) {
(0, psdWriter_1.writeUint32)(writer, 0);
(0, psdWriter_1.writeUint32)(writer, length);
}
addHandler('TySh', hasKey('text'), function (reader, target, leftBytes) {
if ((0, psdReader_1.readInt16)(reader) !== 1)
throw new Error("Invalid TySh version");
var transform = [];
for (var i = 0; i < 6; i++)
transform.push((0, psdReader_1.readFloat64)(reader));
if ((0, psdReader_1.readInt16)(reader) !== 50)
throw new Error("Invalid TySh text version");
var text = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log(require('util').inspect(text, false, 99, false), 'utf8');
if ((0, psdReader_1.readInt16)(reader) !== 1)
throw new Error("Invalid TySh warp version");
var warp = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log(require('util').inspect(warp, false, 99, false), 'utf8');
target.text = {
transform: transform,
left: (0, psdReader_1.readFloat32)(reader),
top: (0, psdReader_1.readFloat32)(reader),
right: (0, psdReader_1.readFloat32)(reader),
bottom: (0, psdReader_1.readFloat32)(reader),
text: text['Txt '].replace(/\r/g, '\n'),
index: text.TextIndex || 0,
gridding: descriptor_1.textGridding.decode(text.textGridding),
antiAlias: descriptor_1.Annt.decode(text.AntA),
orientation: descriptor_1.Ornt.decode(text.Ornt),
warp: {
style: descriptor_1.warpStyle.decode(warp.warpStyle),
value: warp.warpValue || 0,
perspective: warp.warpPerspective || 0,
perspectiveOther: warp.warpPerspectiveOther || 0,
rotate: descriptor_1.Ornt.decode(warp.warpRotate),
},
};
if (text.bounds)
target.text.bounds = (0, descriptor_1.descBoundsToBounds)(text.bounds);
if (text.boundingBox)
target.text.boundingBox = (0, descriptor_1.descBoundsToBounds)(text.boundingBox);
if (text.EngineData) {
var engineData = (0, engineData_1.parseEngineData)(text.EngineData);
var textData = (0, text_1.decodeEngineData)(engineData);
// console.log(require('util').inspect(engineData, false, 99, false), 'utf8');
// require('fs').writeFileSync(`layer-${target.name}.txt`, require('util').inspect(engineData, false, 99, false), 'utf8');
// const before = parseEngineData(text.EngineData);
// const after = encodeEngineData(engineData);
// require('fs').writeFileSync('before.txt', require('util').inspect(before, false, 99, false), 'utf8');
// require('fs').writeFileSync('after.txt', require('util').inspect(after, false, 99, false), 'utf8');
// console.log(require('util').inspect(parseEngineData(text.EngineData), false, 99, true));
target.text = __assign(__assign({}, target.text), textData);
// console.log(require('util').inspect(target.text, false, 99, true));
}
(0, psdReader_1.skipBytes)(reader, leftBytes());
}, function (writer, target) {
var text = target.text;
var warp = text.warp || {};
var transform = text.transform || [1, 0, 0, 1, 0, 0];
var textDescriptor = __assign(__assign(__assign({ 'Txt ': (text.text || '').replace(/\r?\n/g, '\r'), textGridding: descriptor_1.textGridding.encode(text.gridding), Ornt: descriptor_1.Ornt.encode(text.orientation), AntA: descriptor_1.Annt.encode(text.antiAlias) }, (text.bounds ? { bounds: (0, descriptor_1.boundsToDescBounds)(text.bounds) } : {})), (text.boundingBox ? { boundingBox: (0, descriptor_1.boundsToDescBounds)(text.boundingBox) } : {})), { TextIndex: text.index || 0, EngineData: (0, engineData_1.serializeEngineData)((0, text_1.encodeEngineData)(text)) });
(0, psdWriter_1.writeInt16)(writer, 1); // version
for (var i = 0; i < 6; i++) {
(0, psdWriter_1.writeFloat64)(writer, transform[i]);
}
(0, psdWriter_1.writeInt16)(writer, 50); // text version
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'TxLr', textDescriptor, 'text');
(0, psdWriter_1.writeInt16)(writer, 1); // warp version
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'warp', encodeWarp(warp));
(0, psdWriter_1.writeFloat32)(writer, text.left);
(0, psdWriter_1.writeFloat32)(writer, text.top);
(0, psdWriter_1.writeFloat32)(writer, text.right);
(0, psdWriter_1.writeFloat32)(writer, text.bottom);
// writeZeros(writer, 2);
});
// vector fills
addHandler('SoCo', function (target) { return target.vectorFill !== undefined && target.vectorStroke === undefined &&
target.vectorFill.type === 'color'; }, function (reader, target) {
var descriptor = (0, descriptor_1.readVersionAndDescriptor)(reader);
target.vectorFill = (0, descriptor_1.parseVectorContent)(descriptor);
}, function (writer, target) {
var descriptor = (0, descriptor_1.serializeVectorContent)(target.vectorFill).descriptor;
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
});
addHandler('GdFl', function (target) { return target.vectorFill !== undefined && target.vectorStroke === undefined &&
(target.vectorFill.type === 'solid' || target.vectorFill.type === 'noise'); }, function (reader, target, left) {
var descriptor = (0, descriptor_1.readVersionAndDescriptor)(reader);
target.vectorFill = (0, descriptor_1.parseVectorContent)(descriptor);
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target) {
var descriptor = (0, descriptor_1.serializeVectorContent)(target.vectorFill).descriptor;
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
});
addHandler('PtFl', function (target) { return target.vectorFill !== undefined && target.vectorStroke === undefined &&
target.vectorFill.type === 'pattern'; }, function (reader, target) {
var descriptor = (0, descriptor_1.readVersionAndDescriptor)(reader);
target.vectorFill = (0, descriptor_1.parseVectorContent)(descriptor);
}, function (writer, target) {
var descriptor = (0, descriptor_1.serializeVectorContent)(target.vectorFill).descriptor;
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
});
addHandler('vscg', function (target) { return target.vectorFill !== undefined && target.vectorStroke !== undefined; }, function (reader, target, left) {
(0, psdReader_1.readSignature)(reader); // key
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
target.vectorFill = (0, descriptor_1.parseVectorContent)(desc);
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target) {
var _a = (0, descriptor_1.serializeVectorContent)(target.vectorFill), descriptor = _a.descriptor, key = _a.key;
(0, psdWriter_1.writeSignature)(writer, key);
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', descriptor);
});
function readBezierKnot(reader, width, height) {
var y0 = (0, psdReader_1.readFixedPointPath32)(reader) * height;
var x0 = (0, psdReader_1.readFixedPointPath32)(reader) * width;
var y1 = (0, psdReader_1.readFixedPointPath32)(reader) * height;
var x1 = (0, psdReader_1.readFixedPointPath32)(reader) * width;
var y2 = (0, psdReader_1.readFixedPointPath32)(reader) * height;
var x2 = (0, psdReader_1.readFixedPointPath32)(reader) * width;
return [x0, y0, x1, y1, x2, y2];
}
exports.readBezierKnot = readBezierKnot;
function writeBezierKnot(writer, points, width, height) {
(0, psdWriter_1.writeFixedPointPath32)(writer, points[1] / height); // y0
(0, psdWriter_1.writeFixedPointPath32)(writer, points[0] / width); // x0
(0, psdWriter_1.writeFixedPointPath32)(writer, points[3] / height); // y1
(0, psdWriter_1.writeFixedPointPath32)(writer, points[2] / width); // x1
(0, psdWriter_1.writeFixedPointPath32)(writer, points[5] / height); // y2
(0, psdWriter_1.writeFixedPointPath32)(writer, points[4] / width); // x2
}
exports.booleanOperations = ['exclude', 'combine', 'subtract', 'intersect'];
function readVectorMask(reader, vectorMask, width, height, size) {
var end = reader.offset + size;
var paths = vectorMask.paths;
var path = undefined;
while ((end - reader.offset) >= 26) {
var selector = (0, psdReader_1.readUint16)(reader);
switch (selector) {
case 0: // Closed subpath length record
case 3: { // Open subpath length record
(0, psdReader_1.readUint16)(reader); // count
var boolOp = (0, psdReader_1.readInt16)(reader);
var flags = (0, psdReader_1.readUint16)(reader); // bit 1 always 1 ?
(0, psdReader_1.skipBytes)(reader, 18);
path = {
open: selector === 3,
knots: [],
fillRule: flags === 2 ? 'non-zero' : 'even-odd',
};
if (boolOp !== -1)
path.operation = exports.booleanOperations[boolOp];
paths.push(path);
break;
}
case 1: // Closed subpath Bezier knot, linked
case 2: // Closed subpath Bezier knot, unlinked
case 4: // Open subpath Bezier knot, linked
case 5: // Open subpath Bezier knot, unlinked
path.knots.push({ linked: (selector === 1 || selector === 4), points: readBezierKnot(reader, width, height) });
break;
case 6: // Path fill rule record
(0, psdReader_1.skipBytes)(reader, 24);
break;
case 7: { // Clipboard record
// TODO: check if these need to be multiplied by document size
var top_1 = (0, psdReader_1.readFixedPointPath32)(reader);
var left = (0, psdReader_1.readFixedPointPath32)(reader);
var bottom = (0, psdReader_1.readFixedPointPath32)(reader);
var right = (0, psdReader_1.readFixedPointPath32)(reader);
var resolution = (0, psdReader_1.readFixedPointPath32)(reader);
(0, psdReader_1.skipBytes)(reader, 4);
vectorMask.clipboard = { top: top_1, left: left, bottom: bottom, right: right, resolution: resolution };
break;
}
case 8: // Initial fill rule record
vectorMask.fillStartsWithAllPixels = !!(0, psdReader_1.readUint16)(reader);
(0, psdReader_1.skipBytes)(reader, 22);
break;
default: throw new Error('Invalid vmsk section');
}
}
return paths;
}
exports.readVectorMask = readVectorMask;
addHandler('vmsk', hasKey('vectorMask'), function (reader, target, left, _a) {
var width = _a.width, height = _a.height;
if ((0, psdReader_1.readUint32)(reader) !== 3)
throw new Error('Invalid vmsk version');
target.vectorMask = { paths: [] };
var vectorMask = target.vectorMask;
var flags = (0, psdReader_1.readUint32)(reader);
vectorMask.invert = (flags & 1) !== 0;
vectorMask.notLink = (flags & 2) !== 0;
vectorMask.disable = (flags & 4) !== 0;
readVectorMask(reader, vectorMask, width, height, left());
// drawBezierPaths(vectorMask.paths, width, height, 'out.png');
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target, _a) {
var width = _a.width, height = _a.height;
var vectorMask = target.vectorMask;
var flags = (vectorMask.invert ? 1 : 0) |
(vectorMask.notLink ? 2 : 0) |
(vectorMask.disable ? 4 : 0);
(0, psdWriter_1.writeUint32)(writer, 3); // version
(0, psdWriter_1.writeUint32)(writer, flags);
// initial entry
(0, psdWriter_1.writeUint16)(writer, 6);
(0, psdWriter_1.writeZeros)(writer, 24);
var clipboard = vectorMask.clipboard;
if (clipboard) {
(0, psdWriter_1.writeUint16)(writer, 7);
(0, psdWriter_1.writeFixedPointPath32)(writer, clipboard.top);
(0, psdWriter_1.writeFixedPointPath32)(writer, clipboard.left);
(0, psdWriter_1.writeFixedPointPath32)(writer, clipboard.bottom);
(0, psdWriter_1.writeFixedPointPath32)(writer, clipboard.right);
(0, psdWriter_1.writeFixedPointPath32)(writer, clipboard.resolution);
(0, psdWriter_1.writeZeros)(writer, 4);
}
if (vectorMask.fillStartsWithAllPixels !== undefined) {
(0, psdWriter_1.writeUint16)(writer, 8);
(0, psdWriter_1.writeUint16)(writer, vectorMask.fillStartsWithAllPixels ? 1 : 0);
(0, psdWriter_1.writeZeros)(writer, 22);
}
for (var _i = 0, _b = vectorMask.paths; _i < _b.length; _i++) {
var path = _b[_i];
(0, psdWriter_1.writeUint16)(writer, path.open ? 3 : 0);
(0, psdWriter_1.writeUint16)(writer, path.knots.length);
(0, psdWriter_1.writeUint16)(writer, path.operation ? exports.booleanOperations.indexOf(path.operation) : -1); // -1 for undefined
(0, psdWriter_1.writeUint16)(writer, path.fillRule === 'non-zero' ? 2 : 1);
(0, psdWriter_1.writeZeros)(writer, 18); // TODO: these are sometimes non-zero
var linkedKnot = path.open ? 4 : 1;
var unlinkedKnot = path.open ? 5 : 2;
for (var _c = 0, _d = path.knots; _c < _d.length; _c++) {
var _e = _d[_c], linked = _e.linked, points = _e.points;
(0, psdWriter_1.writeUint16)(writer, linked ? linkedKnot : unlinkedKnot);
writeBezierKnot(writer, points, width, height);
}
}
});
// TODO: need to write vmsk if has outline ?
addHandlerAlias('vsms', 'vmsk');
// addHandlerAlias('vmsk', 'vsms');
addHandler('vowv', // something with vectors?
hasKey('vowv'), function (reader, target) {
target.vowv = (0, psdReader_1.readUint32)(reader); // always 2 ????
}, function (writer, target) {
(0, psdWriter_1.writeUint32)(writer, target.vowv);
});
addHandler('vogk', hasKey('vectorOrigination'), function (reader, target, left) {
if ((0, psdReader_1.readInt32)(reader) !== 1)
throw new Error("Invalid vogk version");
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log(require('util').inspect(desc, false, 99, true));
target.vectorOrigination = { keyDescriptorList: [] };
for (var _i = 0, _a = desc.keyDescriptorList; _i < _a.length; _i++) {
var i = _a[_i];
var item = {};
if (i.keyShapeInvalidated != null)
item.keyShapeInvalidated = i.keyShapeInvalidated;
if (i.keyOriginType != null)
item.keyOriginType = i.keyOriginType;
if (i.keyOriginResolution != null)
item.keyOriginResolution = i.keyOriginResolution;
if (i.keyOriginShapeBBox) {
item.keyOriginShapeBoundingBox = {
top: (0, descriptor_1.parseUnitsOrNumber)(i.keyOriginShapeBBox['Top ']),
left: (0, descriptor_1.parseUnitsOrNumber)(i.keyOriginShapeBBox.Left),
bottom: (0, descriptor_1.parseUnitsOrNumber)(i.keyOriginShapeBBox.Btom),
right: (0, descriptor_1.parseUnitsOrNumber)(i.keyOriginShapeBBox.Rght),
};
}
var rectRadii = i.keyOriginRRectRadii;
if (rectRadii) {
item.keyOriginRRectRadii = {
topRight: (0, descriptor_1.parseUnits)(rectRadii.topRight),
topLeft: (0, descriptor_1.parseUnits)(rectRadii.topLeft),
bottomLeft: (0, descriptor_1.parseUnits)(rectRadii.bottomLeft),
bottomRight: (0, descriptor_1.parseUnits)(rectRadii.bottomRight),
};
}
var corners = i.keyOriginBoxCorners;
if (corners) {
item.keyOriginBoxCorners = [
{ x: corners.rectangleCornerA.Hrzn, y: corners.rectangleCornerA.Vrtc },
{ x: corners.rectangleCornerB.Hrzn, y: corners.rectangleCornerB.Vrtc },
{ x: corners.rectangleCornerC.Hrzn, y: corners.rectangleCornerC.Vrtc },
{ x: corners.rectangleCornerD.Hrzn, y: corners.rectangleCornerD.Vrtc },
];
}
var trnf = i.Trnf;
if (trnf) {
item.transform = [trnf.xx, trnf.xy, trnf.xy, trnf.yy, trnf.tx, trnf.ty];
}
target.vectorOrigination.keyDescriptorList.push(item);
}
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target) {
target;
var orig = target.vectorOrigination;
var desc = { keyDescriptorList: [] };
for (var i = 0; i < orig.keyDescriptorList.length; i++) {
var item = orig.keyDescriptorList[i];
desc.keyDescriptorList.push({}); // we're adding keyOriginIndex at the end
var out = desc.keyDescriptorList[desc.keyDescriptorList.length - 1];
if (item.keyOriginType != null)
out.keyOriginType = item.keyOriginType;
if (item.keyOriginResolution != null)
out.keyOriginResolution = item.keyOriginResolution;
var radii = item.keyOriginRRectRadii;
if (radii) {
out.keyOriginRRectRadii = {
unitValueQuadVersion: 1,
topRight: (0, descriptor_1.unitsValue)(radii.topRight, 'topRight'),
topLeft: (0, descriptor_1.unitsValue)(radii.topLeft, 'topLeft'),
bottomLeft: (0, descriptor_1.unitsValue)(radii.bottomLeft, 'bottomLeft'),
bottomRight: (0, descriptor_1.unitsValue)(radii.bottomRight, 'bottomRight'),
};
}
var box = item.keyOriginShapeBoundingBox;
if (box) {
out.keyOriginShapeBBox = {
unitValueQuadVersion: 1,
'Top ': (0, descriptor_1.unitsValue)(box.top, 'top'),
Left: (0, descriptor_1.unitsValue)(box.left, 'left'),
Btom: (0, descriptor_1.unitsValue)(box.bottom, 'bottom'),
Rght: (0, descriptor_1.unitsValue)(box.right, 'right'),
};
}
var corners = item.keyOriginBoxCorners;
if (corners && corners.length === 4) {
out.keyOriginBoxCorners = {
rectangleCornerA: { Hrzn: corners[0].x, Vrtc: corners[0].y },
rectangleCornerB: { Hrzn: corners[1].x, Vrtc: corners[1].y },
rectangleCornerC: { Hrzn: corners[2].x, Vrtc: corners[2].y },
rectangleCornerD: { Hrzn: corners[3].x, Vrtc: corners[3].y },
};
}
var transform = item.transform;
if (transform && transform.length === 6) {
out.Trnf = {
xx: transform[0],
xy: transform[1],
yx: transform[2],
yy: transform[3],
tx: transform[4],
ty: transform[5],
};
}
if (item.keyShapeInvalidated != null)
out.keyShapeInvalidated = item.keyShapeInvalidated;
out.keyOriginIndex = i;
}
(0, psdWriter_1.writeInt32)(writer, 1); // version
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
});
addHandler('lmfx', function (target) { return target.effects !== undefined && hasMultiEffects(target.effects); }, function (reader, target, left) {
var version = (0, psdReader_1.readUint32)(reader);
if (version !== 0)
throw new Error('Invalid lmfx version');
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log('READ', require('util').inspect(desc, false, 99, true));
// discard if read in 'lrFX' or 'lfx2' section
target.effects = (0, descriptor_1.parseEffects)(desc, !!reader.logMissingFeatures);
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target, _, options) {
var desc = (0, descriptor_1.serializeEffects)(target.effects, !!options.logMissingFeatures, true);
// console.log('WRITE', require('util').inspect(desc, false, 99, true));
(0, psdWriter_1.writeUint32)(writer, 0); // version
(0, descriptor_1.writeVersionAndDescriptor)(writer, '', 'null', desc);
});
addHandler('lrFX', hasKey('effects'), function (reader, target, left) {
if (!target.effects)
target.effects = (0, effectsHelpers_1.readEffects)(reader);
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target) {
(0, effectsHelpers_1.writeEffects)(writer, target.effects);
});
addHandler('luni', hasKey('name'), function (reader, target, left) {
if (left() > 4) {
var length_1 = (0, psdReader_1.readUint32)(reader);
if (left() >= (length_1 * 2)) {
target.name = (0, psdReader_1.readUnicodeStringWithLength)(reader, length_1);
}
else {
if (reader.logDevFeatures)
reader.log('name in luni section is too long');
}
}
else {
if (reader.logDevFeatures)
reader.log('empty luni section');
}
(0, psdReader_1.skipBytes)(reader, left());
}, function (writer, target) {
(0, psdWriter_1.writeUnicodeString)(writer, target.name);
// writeUint16(writer, 0); // padding (but not extending string length)
});
addHandler('lnsr', hasKey('nameSource'), function (reader, target) { return target.nameSource = (0, psdReader_1.readSignature)(reader); }, function (writer, target) { return (0, psdWriter_1.writeSignature)(writer, target.nameSource); });
addHandler('lyid', hasKey('id'), function (reader, target) {
target.id = (0, psdReader_1.readUint32)(reader);
}, function (writer, target, _psd, options) {
var id = target.id;
while (options.layerIds.has(id))
id += 100; // make sure we don't have duplicate layer ids
(0, psdWriter_1.writeUint32)(writer, id);
options.layerIds.add(id);
options.layerToId.set(target, id);
});
addHandler('lsct', hasKey('sectionDivider'), function (reader, target, left) {
target.sectionDivider = { type: (0, psdReader_1.readUint32)(reader) };
if (left()) {
(0, psdReader_1.checkSignature)(reader, '8BIM');
target.sectionDivider.key = (0, psdReader_1.readSignature)(reader);
}
if (left()) {
target.sectionDivider.subType = (0, psdReader_1.readUint32)(reader);
}
}, function (writer, target) {
(0, psdWriter_1.writeUint32)(writer, target.sectionDivider.type);
if (target.sectionDivider.key) {
(0, psdWriter_1.writeSignature)(writer, '8BIM');
(0, psdWriter_1.writeSignature)(writer, target.sectionDivider.key);
if (target.sectionDivider.subType !== undefined) {
(0, psdWriter_1.writeUint32)(writer, target.sectionDivider.subType);
}
}
});
// it seems lsdk is used when there's a layer is nested more than 6 levels, but I don't know why?
// maybe some limitation of old version of PS?
addHandlerAlias('lsdk', 'lsct');
addHandler('clbl', hasKey('blendClippendElements'), function (reader, target) {
target.blendClippendElements = !!(0, psdReader_1.readUint8)(reader);
(0, psdReader_1.skipBytes)(reader, 3);
}, function (writer, target) {
(0, psdWriter_1.writeUint8)(writer, target.blendClippendElements ? 1 : 0);
(0, psdWriter_1.writeZeros)(writer, 3);
});
addHandler('infx', hasKey('blendInteriorElements'), function (reader, target) {
target.blendInteriorElements = !!(0, psdReader_1.readUint8)(reader);
(0, psdReader_1.skipBytes)(reader, 3);
}, function (writer, target) {
(0, psdWriter_1.writeUint8)(writer, target.blendInteriorElements ? 1 : 0);
(0, psdWriter_1.writeZeros)(writer, 3);
});
addHandler('knko', hasKey('knockout'), function (reader, target) {
target.knockout = !!(0, psdReader_1.readUint8)(reader);
(0, psdReader_1.skipBytes)(reader, 3);
}, function (writer, target) {
(0, psdWriter_1.writeUint8)(writer, target.knockout ? 1 : 0);
(0, psdWriter_1.writeZeros)(writer, 3);
});
addHandler('lmgm', hasKey('layerMaskAsGlobalMask'), function (reader, target) {
target.layerMaskAsGlobalMask = !!(0, psdReader_1.readUint8)(reader);
(0, psdReader_1.skipBytes)(reader, 3);
}, function (writer, target) {
(0, psdWriter_1.writeUint8)(writer, target.layerMaskAsGlobalMask ? 1 : 0);
(0, psdWriter_1.writeZeros)(writer, 3);
});
addHandler('lspf', hasKey('protected'), function (reader, target) {
var flags = (0, psdReader_1.readUint32)(reader);
target.protected = {
transparency: (flags & 0x01) !== 0,
composite: (flags & 0x02) !== 0,
position: (flags & 0x04) !== 0,
};
if (flags & 0x08)
target.protected.artboards = true;
}, function (writer, target) {
var flags = (target.protected.transparency ? 0x01 : 0) |
(target.protected.composite ? 0x02 : 0) |
(target.protected.position ? 0x04 : 0) |
(target.protected.artboards ? 0x08 : 0);
(0, psdWriter_1.writeUint32)(writer, flags);
});
addHandler('lclr', hasKey('layerColor'), function (reader, target) {
var color = (0, psdReader_1.readUint16)(reader);
(0, psdReader_1.skipBytes)(reader, 6);
target.layerColor = helpers_1.layerColors[color];
}, function (writer, target) {
var index = helpers_1.layerColors.indexOf(target.layerColor);
(0, psdWriter_1.writeUint16)(writer, index === -1 ? 0 : index);
(0, psdWriter_1.writeZeros)(writer, 6);
});
addHandler('shmd', // Metadata setting
function (// Metadata setting
target) { return target.timestamp !== undefined || target.animationFrames !== undefined || target.animationFrameFlags !== undefined || target.timeline !== undefined || target.comps !== undefined; }, function (reader, target, left) {
var count = (0, psdReader_1.readUint32)(reader);
var _loop_1 = function (i) {
(0, psdReader_1.checkSignature)(reader, '8BIM');
var key = (0, psdReader_1.readSignature)(reader);
(0, psdReader_1.readUint8)(reader); // copy
(0, psdReader_1.skipBytes)(reader, 3);
(0, psdReader_1.readSection)(reader, 1, function (left) {
if (key === 'cust') {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log('cust', target.name, require('util').inspect(desc, false, 99, true));
if (desc.layerTime !== undefined)
target.timestamp = desc.layerTime;
}
else if (key === 'mlst') {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log('mlst', target.name, require('util').inspect(desc, false, 99, true));
target.animationFrames = [];
for (var i_1 = 0; i_1 < desc.LaSt.length; i_1++) {
var f = desc.LaSt[i_1];
var frame = { frames: f.FrLs };
if (f.enab !== undefined)
frame.enable = f.enab;
if (f.Ofst)
frame.offset = (0, descriptor_1.horzVrtcToXY)(f.Ofst);
if (f.FXRf)
frame.referencePoint = (0, descriptor_1.horzVrtcToXY)(f.FXRf);
if (f.Lefx)
frame.effects = (0, descriptor_1.parseEffects)(f.Lefx, !!reader.logMissingFeatures);
if (f.blendOptions && f.blendOptions.Opct)
frame.opacity = (0, descriptor_1.parsePercent)(f.blendOptions.Opct);
target.animationFrames.push(frame);
}
}
else if (key === 'mdyn') {
// frame flags
(0, psdReader_1.readUint16)(reader); // unknown
var propagate = (0, psdReader_1.readUint8)(reader);
var flags = (0, psdReader_1.readUint8)(reader);
target.animationFrameFlags = {
propagateFrameOne: !propagate,
unifyLayerPosition: (flags & 1) !== 0,
unifyLayerStyle: (flags & 2) !== 0,
unifyLayerVisibility: (flags & 4) !== 0,
};
}
else if (key === 'tmln') {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
var timeScope = desc.timeScope;
// console.log('tmln', target.name, target.id, require('util').inspect(desc, false, 99, true));
var timeline = {
start: (0, descriptor_1.frac)(timeScope.Strt),
duration: (0, descriptor_1.frac)(timeScope.duration),
inTime: (0, descriptor_1.frac)(timeScope.inTime),
outTime: (0, descriptor_1.frac)(timeScope.outTime),
autoScope: desc.autoScope,
audioLevel: desc.audioLevel,
};
if (desc.trackList) {
timeline.tracks = (0, descriptor_1.parseTrackList)(desc.trackList, !!reader.logMissingFeatures);
}
target.timeline = timeline;
// console.log('tmln:result', target.name, target.id, require('util').inspect(timeline, false, 99, true));
}
else if (key === 'cmls') {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log('cmls', require('util').inspect(desc, false, 99, true));
target.comps = {
settings: [],
};
if (desc.origFXRefPoint)
target.comps.originalEffectsReferencePoint = { x: desc.origFXRefPoint.Hrzn, y: desc.origFXRefPoint.Vrtc };
for (var _i = 0, _a = desc.layerSettings; _i < _a.length; _i++) {
var item = _a[_i];
target.comps.settings.push({ compList: item.compList });
var t = target.comps.settings[target.comps.settings.length - 1];
if ('enab' in item)
t.enabled = item.enab;
if (item.Ofst)
t.offset = { x: item.Ofst.Hrzn, y: item.Ofst.Vrtc };
if (item.FXRefPoint)
t.effectsReferencePoint = { x: item.FXRefPoint.Hrzn, y: item.FXRefPoint.Vrtc };
}
}
else if (key === 'extn') {
var desc = (0, descriptor_1.readVersionAndDescriptor)(reader);
// console.log(require('util').inspect(desc, false, 99, true));
desc; // TODO: save this
reader.logMissingFeatures && reader.log('Unhandled "shmd" section key', key);
}
else {
reader.logMissingFeatures && reader