@pixerate/editor 0.185.0 → 0.187.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/dist/{chunk-GYYSPMVU.js → chunk-FW7N64XK.js} +295 -188
- package/dist/{chunk-C6TRAAG4.cjs → chunk-X2KQQZBT.cjs} +355 -248
- package/dist/image-editor/controller.d.cts +89 -0
- package/dist/image-editor/controller.d.ts +89 -0
- package/dist/image-editor/index.cjs +1602 -1030
- package/dist/image-editor/index.js +591 -19
- package/dist/image-editor/layers/model.d.cts +5 -1
- package/dist/image-editor/layers/model.d.ts +5 -1
- package/dist/image-editor/layers/paint-ui.d.cts +2 -1
- package/dist/image-editor/layers/paint-ui.d.ts +2 -1
- package/dist/image-editor/layers/serialize.d.cts +3 -0
- package/dist/image-editor/layers/serialize.d.ts +3 -0
- package/dist/image-editor/psd/channels.d.cts +24 -0
- package/dist/image-editor/psd/channels.d.ts +24 -0
- package/dist/image-editor/psd/export.d.cts +3 -0
- package/dist/image-editor/psd/export.d.ts +3 -0
- package/dist/image-editor/psd/import.d.cts +10 -0
- package/dist/image-editor/psd/import.d.ts +10 -0
- package/dist/image-editor/renderer.d.cts +6 -0
- package/dist/image-editor/renderer.d.ts +6 -0
- package/dist/image-editor/selection/channels.d.cts +52 -0
- package/dist/image-editor/selection/channels.d.ts +52 -0
- package/dist/image-editor/selection/gesture.d.cts +7 -0
- package/dist/image-editor/selection/gesture.d.ts +7 -0
- package/dist/image-editor/selection/index.d.cts +2 -0
- package/dist/image-editor/selection/index.d.ts +2 -0
- package/dist/image-editor/selection/mask-files.d.cts +20 -0
- package/dist/image-editor/selection/mask-files.d.ts +20 -0
- package/dist/image-editor/selection/overlay.d.cts +2 -0
- package/dist/image-editor/selection/overlay.d.ts +2 -0
- package/dist/image-editor/tools.d.cts +3 -1
- package/dist/image-editor/tools.d.ts +3 -1
- package/dist/image-editor/types.d.cts +10 -0
- package/dist/image-editor/types.d.ts +10 -0
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +12 -24
- package/skills/pixerate-image-editor/references/painting.md +29 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +20 -2
|
@@ -6346,6 +6346,192 @@ function encodeLegacyName(s) {
|
|
|
6346
6346
|
return Uint8Array.from(out);
|
|
6347
6347
|
}
|
|
6348
6348
|
|
|
6349
|
+
// src/image-editor/psd/compression.ts
|
|
6350
|
+
var MAX_DECODED_BYTES = 2 ** 31;
|
|
6351
|
+
function rowBytes(width, depth) {
|
|
6352
|
+
return depth === 1 ? Math.ceil(width / 8) : width * Math.max(1, depth >> 3);
|
|
6353
|
+
}
|
|
6354
|
+
function decodedLength(l) {
|
|
6355
|
+
const total = l.planes * l.height * rowBytes(l.width, l.depth);
|
|
6356
|
+
if (total > MAX_DECODED_BYTES) throw new PsdError(`Decoded channel data of ${total} bytes is larger than the ${MAX_DECODED_BYTES}-byte limit.`);
|
|
6357
|
+
return total;
|
|
6358
|
+
}
|
|
6359
|
+
function packbitsBound(n) {
|
|
6360
|
+
return n + Math.ceil(n / 128);
|
|
6361
|
+
}
|
|
6362
|
+
function packbitsEncode(src, out, at) {
|
|
6363
|
+
const n = src.length;
|
|
6364
|
+
let i = 0;
|
|
6365
|
+
while (i < n) {
|
|
6366
|
+
let run = 1;
|
|
6367
|
+
while (i + run < n && run < 128 && src[i + run] === src[i]) run++;
|
|
6368
|
+
if (run >= 2) {
|
|
6369
|
+
out[at++] = 257 - run & 255;
|
|
6370
|
+
out[at++] = src[i];
|
|
6371
|
+
i += run;
|
|
6372
|
+
continue;
|
|
6373
|
+
}
|
|
6374
|
+
const start = i;
|
|
6375
|
+
let len = 0;
|
|
6376
|
+
while (i < n && len < 128) {
|
|
6377
|
+
if (i + 2 < n && src[i] === src[i + 1] && src[i] === src[i + 2]) break;
|
|
6378
|
+
i++;
|
|
6379
|
+
len++;
|
|
6380
|
+
}
|
|
6381
|
+
out[at++] = len - 1;
|
|
6382
|
+
out.set(src.subarray(start, start + len), at);
|
|
6383
|
+
at += len;
|
|
6384
|
+
}
|
|
6385
|
+
return at;
|
|
6386
|
+
}
|
|
6387
|
+
function packbitsDecodeInto(src, expected, out, at) {
|
|
6388
|
+
const target = at + expected;
|
|
6389
|
+
let i = 0;
|
|
6390
|
+
while (at < target) {
|
|
6391
|
+
if (i >= src.length) throw new PsdError("PackBits row ended early.");
|
|
6392
|
+
const h = src[i++];
|
|
6393
|
+
if (h < 128) {
|
|
6394
|
+
const len = h + 1;
|
|
6395
|
+
if (i + len > src.length) throw new PsdError("PackBits literal is truncated.");
|
|
6396
|
+
if (at + len > target) throw new PsdError("PackBits literal overflows its row.");
|
|
6397
|
+
out.set(src.subarray(i, i + len), at);
|
|
6398
|
+
at += len;
|
|
6399
|
+
i += len;
|
|
6400
|
+
} else if (h !== 128) {
|
|
6401
|
+
const len = 257 - h;
|
|
6402
|
+
if (i >= src.length) throw new PsdError("PackBits run is truncated.");
|
|
6403
|
+
const b = src[i++];
|
|
6404
|
+
if (at + len > target) throw new PsdError("PackBits run overflows its row.");
|
|
6405
|
+
out.fill(b, at, at + len);
|
|
6406
|
+
at += len;
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6409
|
+
return at;
|
|
6410
|
+
}
|
|
6411
|
+
function inflateChecked(data, expected) {
|
|
6412
|
+
let out;
|
|
6413
|
+
try {
|
|
6414
|
+
out = inflate(data, { maxOutput: expected + (1 << 20), sizeHint: expected, verify: false });
|
|
6415
|
+
} catch (e) {
|
|
6416
|
+
throw new PsdError(`ZIP channel data: ${e instanceof ZlibError || e instanceof Error ? e.message : String(e)}`);
|
|
6417
|
+
}
|
|
6418
|
+
if (out.length < expected) throw new PsdError(`ZIP stream produced ${out.length} of ${expected} bytes.`);
|
|
6419
|
+
return out.length === expected ? out : out.subarray(0, expected);
|
|
6420
|
+
}
|
|
6421
|
+
function unpredict(buf, l) {
|
|
6422
|
+
const rb = rowBytes(l.width, l.depth);
|
|
6423
|
+
if (rb === 0) return;
|
|
6424
|
+
const w = l.width;
|
|
6425
|
+
const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
|
|
6426
|
+
for (let o = 0; o + rb <= buf.length; o += rb) {
|
|
6427
|
+
if (l.depth === 1 || l.depth === 8) {
|
|
6428
|
+
for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
|
|
6429
|
+
} else if (l.depth === 16) {
|
|
6430
|
+
for (let i = 1; i < w; i++) {
|
|
6431
|
+
const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
|
|
6432
|
+
const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
|
|
6433
|
+
const v = a + b & 65535;
|
|
6434
|
+
buf[o + 2 * i] = v >> 8;
|
|
6435
|
+
buf[o + 2 * i + 1] = v & 255;
|
|
6436
|
+
}
|
|
6437
|
+
} else if (l.depth === 32) {
|
|
6438
|
+
for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
|
|
6439
|
+
scratch.set(buf.subarray(o, o + rb));
|
|
6440
|
+
for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + 4 * i + k] = scratch[k * w + i];
|
|
6441
|
+
} else {
|
|
6442
|
+
throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
|
|
6443
|
+
}
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
function decodeRle(r, l, total) {
|
|
6447
|
+
const rows = l.planes * l.height;
|
|
6448
|
+
const rb = rowBytes(l.width, l.depth);
|
|
6449
|
+
r.checkCount(rows, l.psb ? 4 : 2, "RLE row counts");
|
|
6450
|
+
const counts = new Array(rows);
|
|
6451
|
+
for (let i = 0; i < rows; i++) counts[i] = l.psb ? r.u32() : r.u16();
|
|
6452
|
+
if (total > r.remaining * 130) throw new PsdError("RLE data is too short for its declared size.");
|
|
6453
|
+
const out = new Uint8Array(total);
|
|
6454
|
+
let at = 0;
|
|
6455
|
+
for (const c of counts) at = packbitsDecodeInto(r.bytes(c), rb, out, at);
|
|
6456
|
+
return out;
|
|
6457
|
+
}
|
|
6458
|
+
function decodePlanes(compression, data, l) {
|
|
6459
|
+
const total = decodedLength(l);
|
|
6460
|
+
switch (compression) {
|
|
6461
|
+
case 0:
|
|
6462
|
+
if (data.length < total) throw new PsdError(`Raw channel data has ${data.length} of ${total} bytes.`);
|
|
6463
|
+
return data.slice(0, total);
|
|
6464
|
+
case 1:
|
|
6465
|
+
return decodeRle(new PsdReader(data), l, total);
|
|
6466
|
+
case 2:
|
|
6467
|
+
return inflateChecked(data, total).slice();
|
|
6468
|
+
case 3: {
|
|
6469
|
+
const v = inflateChecked(data, total).slice();
|
|
6470
|
+
unpredict(v, l);
|
|
6471
|
+
return v;
|
|
6472
|
+
}
|
|
6473
|
+
default:
|
|
6474
|
+
throw new PsdError(`Unsupported compression method ${compression}.`);
|
|
6475
|
+
}
|
|
6476
|
+
}
|
|
6477
|
+
function encodeRle(decoded2, l) {
|
|
6478
|
+
const rows = l.planes * l.height;
|
|
6479
|
+
const rb = rowBytes(l.width, l.depth);
|
|
6480
|
+
const cs = l.psb ? 4 : 2;
|
|
6481
|
+
const packed = new Uint8Array(rows * packbitsBound(rb));
|
|
6482
|
+
let at = 0;
|
|
6483
|
+
const counts = new Uint8Array(rows * cs);
|
|
6484
|
+
for (let row = 0; row < rows; row++) {
|
|
6485
|
+
const start = at;
|
|
6486
|
+
at = packbitsEncode(decoded2.subarray(row * rb, (row + 1) * rb), packed, at);
|
|
6487
|
+
const n = at - start;
|
|
6488
|
+
if (cs === 2) {
|
|
6489
|
+
if (n > 65535) throw new PsdError("An RLE row is longer than 65535 bytes; write a PSB instead.");
|
|
6490
|
+
counts[row * 2] = n >> 8;
|
|
6491
|
+
counts[row * 2 + 1] = n & 255;
|
|
6492
|
+
} else {
|
|
6493
|
+
counts[row * 4] = n >>> 24;
|
|
6494
|
+
counts[row * 4 + 1] = n >>> 16 & 255;
|
|
6495
|
+
counts[row * 4 + 2] = n >>> 8 & 255;
|
|
6496
|
+
counts[row * 4 + 3] = n & 255;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
const out = new Uint8Array(counts.length + at);
|
|
6500
|
+
out.set(counts);
|
|
6501
|
+
out.set(packed.subarray(0, at), counts.length);
|
|
6502
|
+
return out;
|
|
6503
|
+
}
|
|
6504
|
+
function predict(buf, l) {
|
|
6505
|
+
const rb = rowBytes(l.width, l.depth);
|
|
6506
|
+
if (rb === 0) return;
|
|
6507
|
+
const w = l.width;
|
|
6508
|
+
const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
|
|
6509
|
+
for (let o = 0; o + rb <= buf.length; o += rb) {
|
|
6510
|
+
if (l.depth === 1 || l.depth === 8) {
|
|
6511
|
+
for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
|
|
6512
|
+
} else if (l.depth === 16) {
|
|
6513
|
+
for (let i = w - 1; i > 0; i--) {
|
|
6514
|
+
const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
|
|
6515
|
+
const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
|
|
6516
|
+
const v = a - b & 65535;
|
|
6517
|
+
buf[o + 2 * i] = v >> 8;
|
|
6518
|
+
buf[o + 2 * i + 1] = v & 255;
|
|
6519
|
+
}
|
|
6520
|
+
} else if (l.depth === 32) {
|
|
6521
|
+
scratch.set(buf.subarray(o, o + rb));
|
|
6522
|
+
for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + k * w + i] = scratch[4 * i + k];
|
|
6523
|
+
for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
|
|
6524
|
+
} else {
|
|
6525
|
+
throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
|
|
6526
|
+
}
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
function encodeZipPredicted(decoded2, l) {
|
|
6530
|
+
const buf = decoded2.slice();
|
|
6531
|
+
predict(buf, l);
|
|
6532
|
+
return deflate(buf);
|
|
6533
|
+
}
|
|
6534
|
+
|
|
6349
6535
|
// src/image-editor/psd/descriptor.ts
|
|
6350
6536
|
var MAX_DEPTH = 64;
|
|
6351
6537
|
var STRING_IDS = /* @__PURE__ */ new Set(["warp", "list", "time"]);
|
|
@@ -6945,6 +7131,97 @@ function writeAdjustmentBlock(kind, params) {
|
|
|
6945
7131
|
throw new Error(`Unknown adjustment kind "${kind}".`);
|
|
6946
7132
|
}
|
|
6947
7133
|
|
|
7134
|
+
// src/image-editor/psd/channels.ts
|
|
7135
|
+
var hexToRgb2 = (hex) => {
|
|
7136
|
+
const v = parseInt(/^#?([0-9a-f]{6})$/i.exec(hex)?.[1] ?? "ff0000", 16);
|
|
7137
|
+
return [v >> 16 & 255, v >> 8 & 255, v & 255];
|
|
7138
|
+
};
|
|
7139
|
+
var rgbToHex = (r, g, b) => `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
7140
|
+
function alphaChannelResources(channels) {
|
|
7141
|
+
if (!channels.length) return [];
|
|
7142
|
+
const names = new PsdWriter();
|
|
7143
|
+
for (const c of channels) names.pascal(encodeLegacyName(c.name), 1);
|
|
7144
|
+
const unicode = new PsdWriter();
|
|
7145
|
+
for (const c of channels) unicode.unicode(c.name);
|
|
7146
|
+
const display = new PsdWriter();
|
|
7147
|
+
display.u32(1);
|
|
7148
|
+
for (const c of channels) {
|
|
7149
|
+
const [r, g, b] = hexToRgb2(c.color);
|
|
7150
|
+
display.u16(0);
|
|
7151
|
+
for (const v of [r, g, b, 0]) display.u16(v * 257);
|
|
7152
|
+
display.u16(Math.round(Math.min(1, Math.max(0, c.opacity)) * 100));
|
|
7153
|
+
display.u8(c.indicates === "selected" ? 0 : 1);
|
|
7154
|
+
display.u8(0);
|
|
7155
|
+
}
|
|
7156
|
+
return [
|
|
7157
|
+
{ id: 1006, name: "", data: names.result() },
|
|
7158
|
+
{ id: 1045, name: "", data: unicode.result() },
|
|
7159
|
+
{ id: 1077, name: "", data: display.result() }
|
|
7160
|
+
];
|
|
7161
|
+
}
|
|
7162
|
+
function planeTo8(plane, n, depth) {
|
|
7163
|
+
if (depth === 8) return plane.slice(0, n);
|
|
7164
|
+
const out = new Uint8Array(n);
|
|
7165
|
+
const view = new DataView(plane.buffer, plane.byteOffset, plane.byteLength);
|
|
7166
|
+
for (let i = 0; i < n; i++) {
|
|
7167
|
+
if (depth === 16) out[i] = plane[2 * i];
|
|
7168
|
+
else out[i] = Math.round(Math.min(1, Math.max(0, view.getFloat32(4 * i, false))) * 255);
|
|
7169
|
+
}
|
|
7170
|
+
return out;
|
|
7171
|
+
}
|
|
7172
|
+
function readAlphaChannels(planes, header, first, resource2, warn) {
|
|
7173
|
+
const count = header.channels - first;
|
|
7174
|
+
if (count <= 0 || header.depth === 1) return [];
|
|
7175
|
+
const size = rowBytes(header.width, header.depth) * header.height;
|
|
7176
|
+
const n = header.width * header.height;
|
|
7177
|
+
const names = [];
|
|
7178
|
+
const unicode = resource2(1045);
|
|
7179
|
+
if (unicode) {
|
|
7180
|
+
const r = new PsdReader(unicode);
|
|
7181
|
+
while (r.remaining >= 4 && names.length < count) names.push(r.unicode().replace(/\0+$/, ""));
|
|
7182
|
+
} else {
|
|
7183
|
+
const legacy = resource2(1006);
|
|
7184
|
+
if (legacy) {
|
|
7185
|
+
const r = new PsdReader(legacy);
|
|
7186
|
+
while (r.remaining >= 1 && names.length < count) names.push(new TextDecoder("latin1").decode(r.pascal(1)));
|
|
7187
|
+
}
|
|
7188
|
+
}
|
|
7189
|
+
const display = [];
|
|
7190
|
+
const info = resource2(1077);
|
|
7191
|
+
if (info && info.length >= 4) {
|
|
7192
|
+
const r = new PsdReader(info);
|
|
7193
|
+
r.u32();
|
|
7194
|
+
while (r.remaining >= 14 && display.length < count) {
|
|
7195
|
+
r.u16();
|
|
7196
|
+
const [cr, cg, cb] = [r.u16(), r.u16(), r.u16()];
|
|
7197
|
+
r.u16();
|
|
7198
|
+
const opacity = r.u16();
|
|
7199
|
+
const kind = r.u8();
|
|
7200
|
+
r.u8();
|
|
7201
|
+
display.push({ color: rgbToHex(cr >> 8, cg >> 8, cb >> 8), opacity: Math.min(100, opacity) / 100, kind });
|
|
7202
|
+
}
|
|
7203
|
+
}
|
|
7204
|
+
const out = [];
|
|
7205
|
+
for (let i = 0; i < count; i++) {
|
|
7206
|
+
const start = (first + i) * size;
|
|
7207
|
+
if (start + size > planes.length) break;
|
|
7208
|
+
const d = display[i];
|
|
7209
|
+
const name = names[i] || `Alpha ${i + 1}`;
|
|
7210
|
+
if (d?.kind === 2) {
|
|
7211
|
+
warn(`Spot colour channel "${name}" is not supported and was left out.`);
|
|
7212
|
+
continue;
|
|
7213
|
+
}
|
|
7214
|
+
out.push({
|
|
7215
|
+
name,
|
|
7216
|
+
data: planeTo8(planes.subarray(start, start + size), n, header.depth),
|
|
7217
|
+
color: d?.color ?? "#ff0000",
|
|
7218
|
+
opacity: d?.opacity ?? 0.5,
|
|
7219
|
+
indicates: d?.kind === 0 ? "selected" : "masked"
|
|
7220
|
+
});
|
|
7221
|
+
}
|
|
7222
|
+
return out;
|
|
7223
|
+
}
|
|
7224
|
+
|
|
6948
7225
|
// src/image-editor/psd/paths.ts
|
|
6949
7226
|
var RECORD = 26;
|
|
6950
7227
|
var fixed = (v) => v / 16777216;
|
|
@@ -8129,192 +8406,6 @@ function tyShForLayer(layer) {
|
|
|
8129
8406
|
return writeTySh({ transform: textMatrix(layer), text: text3, warp, tail: new Uint8Array(16) });
|
|
8130
8407
|
}
|
|
8131
8408
|
|
|
8132
|
-
// src/image-editor/psd/compression.ts
|
|
8133
|
-
var MAX_DECODED_BYTES = 2 ** 31;
|
|
8134
|
-
function rowBytes(width, depth) {
|
|
8135
|
-
return depth === 1 ? Math.ceil(width / 8) : width * Math.max(1, depth >> 3);
|
|
8136
|
-
}
|
|
8137
|
-
function decodedLength(l) {
|
|
8138
|
-
const total = l.planes * l.height * rowBytes(l.width, l.depth);
|
|
8139
|
-
if (total > MAX_DECODED_BYTES) throw new PsdError(`Decoded channel data of ${total} bytes is larger than the ${MAX_DECODED_BYTES}-byte limit.`);
|
|
8140
|
-
return total;
|
|
8141
|
-
}
|
|
8142
|
-
function packbitsBound(n) {
|
|
8143
|
-
return n + Math.ceil(n / 128);
|
|
8144
|
-
}
|
|
8145
|
-
function packbitsEncode(src, out, at) {
|
|
8146
|
-
const n = src.length;
|
|
8147
|
-
let i = 0;
|
|
8148
|
-
while (i < n) {
|
|
8149
|
-
let run = 1;
|
|
8150
|
-
while (i + run < n && run < 128 && src[i + run] === src[i]) run++;
|
|
8151
|
-
if (run >= 2) {
|
|
8152
|
-
out[at++] = 257 - run & 255;
|
|
8153
|
-
out[at++] = src[i];
|
|
8154
|
-
i += run;
|
|
8155
|
-
continue;
|
|
8156
|
-
}
|
|
8157
|
-
const start = i;
|
|
8158
|
-
let len = 0;
|
|
8159
|
-
while (i < n && len < 128) {
|
|
8160
|
-
if (i + 2 < n && src[i] === src[i + 1] && src[i] === src[i + 2]) break;
|
|
8161
|
-
i++;
|
|
8162
|
-
len++;
|
|
8163
|
-
}
|
|
8164
|
-
out[at++] = len - 1;
|
|
8165
|
-
out.set(src.subarray(start, start + len), at);
|
|
8166
|
-
at += len;
|
|
8167
|
-
}
|
|
8168
|
-
return at;
|
|
8169
|
-
}
|
|
8170
|
-
function packbitsDecodeInto(src, expected, out, at) {
|
|
8171
|
-
const target = at + expected;
|
|
8172
|
-
let i = 0;
|
|
8173
|
-
while (at < target) {
|
|
8174
|
-
if (i >= src.length) throw new PsdError("PackBits row ended early.");
|
|
8175
|
-
const h = src[i++];
|
|
8176
|
-
if (h < 128) {
|
|
8177
|
-
const len = h + 1;
|
|
8178
|
-
if (i + len > src.length) throw new PsdError("PackBits literal is truncated.");
|
|
8179
|
-
if (at + len > target) throw new PsdError("PackBits literal overflows its row.");
|
|
8180
|
-
out.set(src.subarray(i, i + len), at);
|
|
8181
|
-
at += len;
|
|
8182
|
-
i += len;
|
|
8183
|
-
} else if (h !== 128) {
|
|
8184
|
-
const len = 257 - h;
|
|
8185
|
-
if (i >= src.length) throw new PsdError("PackBits run is truncated.");
|
|
8186
|
-
const b = src[i++];
|
|
8187
|
-
if (at + len > target) throw new PsdError("PackBits run overflows its row.");
|
|
8188
|
-
out.fill(b, at, at + len);
|
|
8189
|
-
at += len;
|
|
8190
|
-
}
|
|
8191
|
-
}
|
|
8192
|
-
return at;
|
|
8193
|
-
}
|
|
8194
|
-
function inflateChecked(data, expected) {
|
|
8195
|
-
let out;
|
|
8196
|
-
try {
|
|
8197
|
-
out = inflate(data, { maxOutput: expected + (1 << 20), sizeHint: expected, verify: false });
|
|
8198
|
-
} catch (e) {
|
|
8199
|
-
throw new PsdError(`ZIP channel data: ${e instanceof ZlibError || e instanceof Error ? e.message : String(e)}`);
|
|
8200
|
-
}
|
|
8201
|
-
if (out.length < expected) throw new PsdError(`ZIP stream produced ${out.length} of ${expected} bytes.`);
|
|
8202
|
-
return out.length === expected ? out : out.subarray(0, expected);
|
|
8203
|
-
}
|
|
8204
|
-
function unpredict(buf, l) {
|
|
8205
|
-
const rb = rowBytes(l.width, l.depth);
|
|
8206
|
-
if (rb === 0) return;
|
|
8207
|
-
const w = l.width;
|
|
8208
|
-
const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
|
|
8209
|
-
for (let o = 0; o + rb <= buf.length; o += rb) {
|
|
8210
|
-
if (l.depth === 1 || l.depth === 8) {
|
|
8211
|
-
for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
|
|
8212
|
-
} else if (l.depth === 16) {
|
|
8213
|
-
for (let i = 1; i < w; i++) {
|
|
8214
|
-
const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
|
|
8215
|
-
const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
|
|
8216
|
-
const v = a + b & 65535;
|
|
8217
|
-
buf[o + 2 * i] = v >> 8;
|
|
8218
|
-
buf[o + 2 * i + 1] = v & 255;
|
|
8219
|
-
}
|
|
8220
|
-
} else if (l.depth === 32) {
|
|
8221
|
-
for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
|
|
8222
|
-
scratch.set(buf.subarray(o, o + rb));
|
|
8223
|
-
for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + 4 * i + k] = scratch[k * w + i];
|
|
8224
|
-
} else {
|
|
8225
|
-
throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
|
|
8226
|
-
}
|
|
8227
|
-
}
|
|
8228
|
-
}
|
|
8229
|
-
function decodeRle(r, l, total) {
|
|
8230
|
-
const rows = l.planes * l.height;
|
|
8231
|
-
const rb = rowBytes(l.width, l.depth);
|
|
8232
|
-
r.checkCount(rows, l.psb ? 4 : 2, "RLE row counts");
|
|
8233
|
-
const counts = new Array(rows);
|
|
8234
|
-
for (let i = 0; i < rows; i++) counts[i] = l.psb ? r.u32() : r.u16();
|
|
8235
|
-
if (total > r.remaining * 130) throw new PsdError("RLE data is too short for its declared size.");
|
|
8236
|
-
const out = new Uint8Array(total);
|
|
8237
|
-
let at = 0;
|
|
8238
|
-
for (const c of counts) at = packbitsDecodeInto(r.bytes(c), rb, out, at);
|
|
8239
|
-
return out;
|
|
8240
|
-
}
|
|
8241
|
-
function decodePlanes(compression, data, l) {
|
|
8242
|
-
const total = decodedLength(l);
|
|
8243
|
-
switch (compression) {
|
|
8244
|
-
case 0:
|
|
8245
|
-
if (data.length < total) throw new PsdError(`Raw channel data has ${data.length} of ${total} bytes.`);
|
|
8246
|
-
return data.slice(0, total);
|
|
8247
|
-
case 1:
|
|
8248
|
-
return decodeRle(new PsdReader(data), l, total);
|
|
8249
|
-
case 2:
|
|
8250
|
-
return inflateChecked(data, total).slice();
|
|
8251
|
-
case 3: {
|
|
8252
|
-
const v = inflateChecked(data, total).slice();
|
|
8253
|
-
unpredict(v, l);
|
|
8254
|
-
return v;
|
|
8255
|
-
}
|
|
8256
|
-
default:
|
|
8257
|
-
throw new PsdError(`Unsupported compression method ${compression}.`);
|
|
8258
|
-
}
|
|
8259
|
-
}
|
|
8260
|
-
function encodeRle(decoded2, l) {
|
|
8261
|
-
const rows = l.planes * l.height;
|
|
8262
|
-
const rb = rowBytes(l.width, l.depth);
|
|
8263
|
-
const cs = l.psb ? 4 : 2;
|
|
8264
|
-
const packed = new Uint8Array(rows * packbitsBound(rb));
|
|
8265
|
-
let at = 0;
|
|
8266
|
-
const counts = new Uint8Array(rows * cs);
|
|
8267
|
-
for (let row = 0; row < rows; row++) {
|
|
8268
|
-
const start = at;
|
|
8269
|
-
at = packbitsEncode(decoded2.subarray(row * rb, (row + 1) * rb), packed, at);
|
|
8270
|
-
const n = at - start;
|
|
8271
|
-
if (cs === 2) {
|
|
8272
|
-
if (n > 65535) throw new PsdError("An RLE row is longer than 65535 bytes; write a PSB instead.");
|
|
8273
|
-
counts[row * 2] = n >> 8;
|
|
8274
|
-
counts[row * 2 + 1] = n & 255;
|
|
8275
|
-
} else {
|
|
8276
|
-
counts[row * 4] = n >>> 24;
|
|
8277
|
-
counts[row * 4 + 1] = n >>> 16 & 255;
|
|
8278
|
-
counts[row * 4 + 2] = n >>> 8 & 255;
|
|
8279
|
-
counts[row * 4 + 3] = n & 255;
|
|
8280
|
-
}
|
|
8281
|
-
}
|
|
8282
|
-
const out = new Uint8Array(counts.length + at);
|
|
8283
|
-
out.set(counts);
|
|
8284
|
-
out.set(packed.subarray(0, at), counts.length);
|
|
8285
|
-
return out;
|
|
8286
|
-
}
|
|
8287
|
-
function predict(buf, l) {
|
|
8288
|
-
const rb = rowBytes(l.width, l.depth);
|
|
8289
|
-
if (rb === 0) return;
|
|
8290
|
-
const w = l.width;
|
|
8291
|
-
const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
|
|
8292
|
-
for (let o = 0; o + rb <= buf.length; o += rb) {
|
|
8293
|
-
if (l.depth === 1 || l.depth === 8) {
|
|
8294
|
-
for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
|
|
8295
|
-
} else if (l.depth === 16) {
|
|
8296
|
-
for (let i = w - 1; i > 0; i--) {
|
|
8297
|
-
const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
|
|
8298
|
-
const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
|
|
8299
|
-
const v = a - b & 65535;
|
|
8300
|
-
buf[o + 2 * i] = v >> 8;
|
|
8301
|
-
buf[o + 2 * i + 1] = v & 255;
|
|
8302
|
-
}
|
|
8303
|
-
} else if (l.depth === 32) {
|
|
8304
|
-
scratch.set(buf.subarray(o, o + rb));
|
|
8305
|
-
for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + k * w + i] = scratch[4 * i + k];
|
|
8306
|
-
for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
|
|
8307
|
-
} else {
|
|
8308
|
-
throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
|
|
8309
|
-
}
|
|
8310
|
-
}
|
|
8311
|
-
}
|
|
8312
|
-
function encodeZipPredicted(decoded2, l) {
|
|
8313
|
-
const buf = decoded2.slice();
|
|
8314
|
-
predict(buf, l);
|
|
8315
|
-
return deflate(buf);
|
|
8316
|
-
}
|
|
8317
|
-
|
|
8318
8409
|
// src/image-editor/psd/smart.ts
|
|
8319
8410
|
var dbl2 = (value) => ({ type: "doub", value });
|
|
8320
8411
|
var unit2 = (u, value) => ({ type: "UntF", unit: u, value });
|
|
@@ -10361,6 +10452,16 @@ function psdToLayers(file, options = {}) {
|
|
|
10361
10452
|
const bg = mergedLayer(ctx);
|
|
10362
10453
|
if (bg) layers = [bg];
|
|
10363
10454
|
}
|
|
10455
|
+
let alphaChannels = [];
|
|
10456
|
+
const hasTransparency = header.channels > ctx.colorCount && (file.layers.length === 0 || file.mergedAlpha);
|
|
10457
|
+
const firstAlpha = ctx.colorCount + (hasTransparency ? 1 : 0);
|
|
10458
|
+
if (!ctx.skipPixels && header.channels > firstAlpha) {
|
|
10459
|
+
try {
|
|
10460
|
+
alphaChannels = readAlphaChannels(decodeMergedImage(file), header, firstAlpha, (id) => resource(file, id), (m) => warn.extra.push(m));
|
|
10461
|
+
} catch (e) {
|
|
10462
|
+
warn.extra.push(`The alpha channels could not be read (${e instanceof Error ? e.message : String(e)}).`);
|
|
10463
|
+
}
|
|
10464
|
+
}
|
|
10364
10465
|
const i32 = (b) => b && b.length >= 4 ? new DataView(b.buffer, b.byteOffset, 4).getInt32(0) : void 0;
|
|
10365
10466
|
const angle = i32(resource(file, 1037));
|
|
10366
10467
|
const altitude = i32(resource(file, 1049));
|
|
@@ -10374,6 +10475,7 @@ function psdToLayers(file, options = {}) {
|
|
|
10374
10475
|
patterns: [...ctx.patterns.values()],
|
|
10375
10476
|
...angle !== void 0 || altitude !== void 0 ? { globalLight: { angle: Math.max(-360, Math.min(360, angle ?? 120)), altitude: Math.max(0, Math.min(90, altitude ?? 30)) } } : {},
|
|
10376
10477
|
info: { psb: header.psb, depth: header.depth, colorMode: mode, channels: header.channels },
|
|
10478
|
+
...alphaChannels.length ? { alphaChannels } : {},
|
|
10377
10479
|
...cmykProfile ? { sourceMode: { mode: "cmyk", profile: cmykProfile } } : header.colorMode === MODE_LAB ? { sourceMode: { mode: "lab" } } : {},
|
|
10378
10480
|
...resource(file, 1039) ? { iccProfile: resource(file, 1039).slice() } : {},
|
|
10379
10481
|
bitDepth: (header.depth === 16 || header.depth === 32) && header.colorMode !== MODE_INDEXED && header.colorMode !== MODE_BITMAP ? header.depth : 8
|
|
@@ -11411,6 +11513,10 @@ function exportPsd(input) {
|
|
|
11411
11513
|
planes = transparent ? dp : dp.slice(0, 3);
|
|
11412
11514
|
}
|
|
11413
11515
|
}
|
|
11516
|
+
for (const ch of input.alphaChannels ?? []) {
|
|
11517
|
+
if (ch.data.length !== n) throw new PsdError(`Alpha channel "${ch.name}" has ${ch.data.length} values, expected ${n}.`);
|
|
11518
|
+
planes.push(planeAtDepth(ch.data, depth));
|
|
11519
|
+
}
|
|
11414
11520
|
const planeBytes = n * (depth >> 3);
|
|
11415
11521
|
const merged2 = new Uint8Array(planeBytes * planes.length);
|
|
11416
11522
|
planes.forEach((p, i) => merged2.set(p, i * planeBytes));
|
|
@@ -11432,6 +11538,7 @@ function exportPsd(input) {
|
|
|
11432
11538
|
{ id: 1057, name: "", data: version.result() }
|
|
11433
11539
|
];
|
|
11434
11540
|
if (input.iccProfile?.length) resources.push({ id: 1039, name: "", data: input.iccProfile });
|
|
11541
|
+
resources.push(...alphaChannelResources(input.alphaChannels ?? []));
|
|
11435
11542
|
if (input.globalLight) {
|
|
11436
11543
|
const i32 = (v) => {
|
|
11437
11544
|
const w = new PsdWriter();
|
|
@@ -11820,6 +11927,8 @@ export {
|
|
|
11820
11927
|
deserializeLayer,
|
|
11821
11928
|
deserializeLayers,
|
|
11822
11929
|
PsdError,
|
|
11930
|
+
decodePlanes,
|
|
11931
|
+
encodeRle,
|
|
11823
11932
|
parseVersionedDescriptor,
|
|
11824
11933
|
versionedDescriptorBytes,
|
|
11825
11934
|
ADJUSTMENT_KEYS,
|
|
@@ -11829,8 +11938,6 @@ export {
|
|
|
11829
11938
|
parseLfx2,
|
|
11830
11939
|
writeLfx2,
|
|
11831
11940
|
parseLrfx,
|
|
11832
|
-
decodePlanes,
|
|
11833
|
-
encodeRle,
|
|
11834
11941
|
BROWSER_IMAGE_TYPES,
|
|
11835
11942
|
readPsd,
|
|
11836
11943
|
layerName,
|