image-in-browser
Version:
Package for encoding / decoding images, transforming images, applying filters, drawing primitives on images on the client side (no need for server Node.js)
426 lines • 18.8 kB
JavaScript
import { InputBuffer } from '../../common/input-buffer.js';
import { LibError } from '../../error/lib-error.js';
import { PsdBevelEffect } from './effect/psd-bevel-effect.js';
import { PsdDropShadowEffect } from './effect/psd-drop-shadow-effect.js';
import { PsdInnerGlowEffect } from './effect/psd-inner-glow-effect.js';
import { PsdInnerShadowEffect } from './effect/psd-inner-shadow-effect.js';
import { PsdOuterGlowEffect } from './effect/psd-outer-glow-effect.js';
import { PsdSolidFillEffect } from './effect/psd-solid-fill-effect.js';
import { PsdLayerDataFactory } from './layer-data/psd-layer-data-factory.js';
import { PsdLayerSectionDivider } from './layer-data/psd-layer-section-divider.js';
import { PsdBlendingRanges } from './psd-blending-ranges.js';
import { PsdChannel } from './psd-channel.js';
import { PsdFlag } from './psd-flag.js';
import { PsdImage } from './psd-image.js';
import { PsdMask } from './psd-mask.js';
export class PsdLayer {
get top() {
return this._top;
}
get left() {
return this._left;
}
get bottom() {
return this._bottom;
}
get right() {
return this._right;
}
get width() {
return this._width;
}
get height() {
return this._height;
}
get blendMode() {
return this._blendMode;
}
get opacity() {
return this._opacity;
}
get clipping() {
return this._clipping;
}
get flags() {
return this._flags;
}
get compression() {
return this._compression;
}
get name() {
return this._name;
}
get channels() {
return this._channels;
}
get mask() {
return this._mask;
}
get blendingRanges() {
return this._blendingRanges;
}
get additionalData() {
return this._additionalData;
}
get children() {
return this._children;
}
get parent() {
return this._parent;
}
get layerImage() {
return this._layerImage;
}
get effects() {
return this._effects;
}
get isVisible() {
return (this._flags & PsdFlag.hidden) === 0;
}
get type() {
if (this._additionalData.has(PsdLayerSectionDivider.tagName)) {
const section = this._additionalData.get(PsdLayerSectionDivider.tagName);
return section.type;
}
return PsdLayerSectionDivider.normal;
}
constructor(input) {
this._additionalData = new Map();
this._children = [];
this._effects = [];
this._top = input.readInt32();
this._left = input.readInt32();
this._bottom = input.readInt32();
this._right = input.readInt32();
this._width = this._right - this._left;
this._height = this._bottom - this._top;
this._channels = [];
const numChannels = input.readUint16();
for (let i = 0; i < numChannels; ++i) {
const id = input.readInt16();
const len = input.readUint32();
this._channels.push(new PsdChannel(id, len));
}
const sig = input.readUint32();
if (sig !== PsdLayer.signature) {
throw new LibError(`Invalid PSD layer signature: ${sig.toString(16)}`);
}
this._blendMode = input.readUint32();
this._opacity = input.read();
this._clipping = input.read();
this._flags = input.read();
const filler = input.read();
if (filler !== 0) {
throw new LibError('Invalid PSD layer data');
}
let len = input.readUint32();
const extra = input.readRange(len);
if (len > 0) {
len = extra.readUint32();
if (len > 0) {
const maskData = extra.readRange(len);
this._mask = new PsdMask(maskData);
}
len = extra.readUint32();
if (len > 0) {
const data = extra.readRange(len);
this._blendingRanges = new PsdBlendingRanges(data);
}
len = extra.read();
this._name = extra.readString(len);
const padding = 4 - (len % 4) - 1;
if (padding > 0) {
extra.skip(padding);
}
while (!extra.isEOS) {
const sig = extra.readUint32();
if (sig !== PsdLayer.signature) {
throw new LibError(`PSD invalid signature for layer additional data: ${sig.toString(16)}`);
}
const tag = extra.readString(4);
len = extra.readUint32();
const data = extra.readRange(len);
if ((len & 1) === 1) {
extra.skip(1);
}
this._additionalData.set(tag, PsdLayerDataFactory.createLayerData(tag, data));
if (tag === 'lrFX') {
const fxData = this._additionalData.get('lrFX');
const data = InputBuffer.from(fxData.data);
data.readUint16();
const numFx = data.readUint16();
for (let j = 0; j < numFx; ++j) {
data.readString(4);
const fxTag = data.readString(4);
const size = data.readUint32();
if (fxTag === 'dsdw') {
const version = data.readUint32();
const blur = data.readUint32();
const intensity = data.readUint32();
const angle = data.readUint32();
const distance = data.readUint32();
const color = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const blendMode = data.readString(8);
const enabled = data.read() !== 0;
const globalAngle = data.read() !== 0;
const opacity = data.read();
const nativeColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
this._effects.push(new PsdDropShadowEffect({
version: version,
blur: blur,
intensity: intensity,
angle: angle,
distance: distance,
color: color,
blendMode: blendMode,
enabled: enabled,
globalAngle: globalAngle,
opacity: opacity,
nativeColor: nativeColor,
}));
}
else if (fxTag === 'isdw') {
const version = data.readUint32();
const blur = data.readUint32();
const intensity = data.readUint32();
const angle = data.readUint32();
const distance = data.readUint32();
const color = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const blendMode = data.readString(8);
const enabled = data.read() !== 0;
const globalAngle = data.read() !== 0;
const opacity = data.read();
const nativeColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
this._effects.push(new PsdInnerShadowEffect({
version: version,
blur: blur,
intensity: intensity,
angle: angle,
distance: distance,
color: color,
blendMode: blendMode,
enabled: enabled,
globalAngle: globalAngle,
opacity: opacity,
nativeColor: nativeColor,
}));
}
else if (fxTag === 'oglw') {
const version = data.readUint32();
const blur = data.readUint32();
const intensity = data.readUint32();
const color = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const blendMode = data.readString(8);
const enabled = data.read() !== 0;
const opacity = data.read();
let nativeColor = undefined;
if (version === 2) {
nativeColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
}
this._effects.push(new PsdOuterGlowEffect({
version: version,
blur: blur,
intensity: intensity,
color: color,
blendMode: blendMode,
enabled: enabled,
opacity: opacity,
nativeColor: nativeColor,
}));
}
else if (fxTag === 'iglw') {
const version = data.readUint32();
const blur = data.readUint32();
const intensity = data.readUint32();
const color = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const blendMode = data.readString(8);
const enabled = data.read() !== 0;
const opacity = data.read();
let invert = undefined;
let nativeColor = undefined;
if (version === 2) {
invert = data.read() !== 0;
nativeColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
}
this._effects.push(new PsdInnerGlowEffect({
version: version,
blur: blur,
intensity: intensity,
color: color,
blendMode: blendMode,
enabled: enabled,
opacity: opacity,
invert: invert,
nativeColor: nativeColor,
}));
}
else if (fxTag === 'bevl') {
const version = data.readUint32();
const angle = data.readUint32();
const strength = data.readUint32();
const blur = data.readUint32();
const highlightBlendMode = data.readString(8);
const shadowBlendMode = data.readString(8);
const highlightColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const shadowColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const bevelStyle = data.read();
const highlightOpacity = data.read();
const shadowOpacity = data.read();
const enabled = data.read() !== 0;
const globalAngle = data.read() !== 0;
const upOrDown = data.read();
let realHighlightColor = undefined;
let realShadowColor = undefined;
if (version === 2) {
realHighlightColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
realShadowColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
}
this._effects.push(new PsdBevelEffect({
version: version,
angle: angle,
strength: strength,
blur: blur,
highlightBlendMode: highlightBlendMode,
shadowBlendMode: shadowBlendMode,
highlightColor: highlightColor,
shadowColor: shadowColor,
bevelStyle: bevelStyle,
highlightOpacity: highlightOpacity,
shadowOpacity: shadowOpacity,
enabled: enabled,
globalAngle: globalAngle,
upOrDown: upOrDown,
realHighlightColor: realHighlightColor,
realShadowColor: realShadowColor,
}));
}
else if (fxTag === 'sofi') {
const version = data.readUint32();
const blendMode = data.readString(4);
const color = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
const opacity = data.read();
const enabled = data.read() !== 0;
const nativeColor = [
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
data.readUint16(),
];
this._effects.push(new PsdSolidFillEffect({
version: version,
blendMode: blendMode,
color: color,
opacity: opacity,
enabled: enabled,
nativeColor: nativeColor,
}));
}
else {
data.skip(size);
}
}
}
}
}
}
getChannel(id) {
for (let i = 0; i < this._channels.length; ++i) {
if (this._channels[i].id === id) {
return this._channels[i];
}
}
return undefined;
}
readImageData(input, psd) {
for (let i = 0; i < this._channels.length; ++i) {
this._channels[i].readPlane({
input: input,
width: this._width,
height: this._height,
bitDepth: psd.depth,
});
}
this._layerImage = PsdImage.createImageFromChannels(this._width, this._height, this._channels, psd.colorMode, psd.depth);
}
}
PsdLayer.signature = 0x3842494d;
//# sourceMappingURL=psd-layer.js.map