@pixerate/editor 0.183.0 → 0.186.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.
Files changed (50) hide show
  1. package/dist/{chunk-Y46OMERN.js → chunk-FW7N64XK.js} +298 -189
  2. package/dist/{chunk-UHMSMUHK.cjs → chunk-X2KQQZBT.cjs} +358 -249
  3. package/dist/image-editor/controller.d.cts +208 -8
  4. package/dist/image-editor/controller.d.ts +208 -8
  5. package/dist/image-editor/index.cjs +2610 -1025
  6. package/dist/image-editor/index.js +1672 -87
  7. package/dist/image-editor/layers/model.d.cts +5 -1
  8. package/dist/image-editor/layers/model.d.ts +5 -1
  9. package/dist/image-editor/layers/paint-ui.d.cts +2 -1
  10. package/dist/image-editor/layers/paint-ui.d.ts +2 -1
  11. package/dist/image-editor/layers/panel.d.cts +23 -1
  12. package/dist/image-editor/layers/panel.d.ts +23 -1
  13. package/dist/image-editor/layers/serialize.d.cts +3 -0
  14. package/dist/image-editor/layers/serialize.d.ts +3 -0
  15. package/dist/image-editor/psd/channels.d.cts +24 -0
  16. package/dist/image-editor/psd/channels.d.ts +24 -0
  17. package/dist/image-editor/psd/export.d.cts +3 -0
  18. package/dist/image-editor/psd/export.d.ts +3 -0
  19. package/dist/image-editor/psd/import.d.cts +10 -0
  20. package/dist/image-editor/psd/import.d.ts +10 -0
  21. package/dist/image-editor/renderer.d.cts +6 -0
  22. package/dist/image-editor/renderer.d.ts +6 -0
  23. package/dist/image-editor/selection/channels.d.cts +52 -0
  24. package/dist/image-editor/selection/channels.d.ts +52 -0
  25. package/dist/image-editor/selection/gesture.d.cts +47 -2
  26. package/dist/image-editor/selection/gesture.d.ts +47 -2
  27. package/dist/image-editor/selection/index.d.cts +2 -0
  28. package/dist/image-editor/selection/index.d.ts +2 -0
  29. package/dist/image-editor/selection/modify.d.cts +3 -2
  30. package/dist/image-editor/selection/modify.d.ts +3 -2
  31. package/dist/image-editor/selection/overlay.d.cts +2 -0
  32. package/dist/image-editor/selection/overlay.d.ts +2 -0
  33. package/dist/image-editor/selection/stroke.d.cts +8 -0
  34. package/dist/image-editor/selection/stroke.d.ts +8 -0
  35. package/dist/image-editor/selection/tool-options.d.cts +12 -2
  36. package/dist/image-editor/selection/tool-options.d.ts +12 -2
  37. package/dist/image-editor/selection/wand.d.cts +37 -0
  38. package/dist/image-editor/selection/wand.d.ts +37 -0
  39. package/dist/image-editor/selection-tools.d.cts +8 -3
  40. package/dist/image-editor/selection-tools.d.ts +8 -3
  41. package/dist/image-editor/tools.d.cts +10 -2
  42. package/dist/image-editor/tools.d.ts +10 -2
  43. package/dist/image-editor/types.d.cts +12 -0
  44. package/dist/image-editor/types.d.ts +12 -0
  45. package/dist/paint-editor/index.cjs +6 -6
  46. package/dist/paint-editor/index.js +1 -1
  47. package/package.json +1 -1
  48. package/skills/pixerate-image-editor/SKILL.md +19 -21
  49. package/skills/pixerate-image-editor/references/free-transform.md +22 -0
  50. package/skills/pixerate-image-selection-masking/SKILL.md +36 -3
@@ -1192,7 +1192,7 @@ function shiftCoverage(src, w, h, amount) {
1192
1192
  for (let i = 0; i < lo.length; i++) lo[i] += (hi[i] - lo[i]) * frac;
1193
1193
  return lo;
1194
1194
  }
1195
- var SELECTION_MODIFY_OPS = ["grow", "shrink", "feather", "border", "smooth"];
1195
+ var SELECTION_MODIFY_OPS = ["expand", "contract", "feather", "border", "smooth", "grow", "shrink"];
1196
1196
  function wrap(mask, coverage) {
1197
1197
  const out = new Uint8Array(coverage.length);
1198
1198
  for (let i = 0; i < out.length; i++) out[i] = coverageToByte(coverage[i]);
@@ -1204,8 +1204,10 @@ function modifySelection(mask, op, radius) {
1204
1204
  const m = selectionToCoverage(mask);
1205
1205
  const { width: w, height: h } = mask;
1206
1206
  switch (op) {
1207
+ case "expand":
1207
1208
  case "grow":
1208
1209
  return wrap(mask, expandCoverage(m, w, h, r));
1210
+ case "contract":
1209
1211
  case "shrink":
1210
1212
  return wrap(mask, contractCoverage(m, w, h, r));
1211
1213
  case "feather":
@@ -6344,6 +6346,192 @@ function encodeLegacyName(s) {
6344
6346
  return Uint8Array.from(out);
6345
6347
  }
6346
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
+
6347
6535
  // src/image-editor/psd/descriptor.ts
6348
6536
  var MAX_DEPTH = 64;
6349
6537
  var STRING_IDS = /* @__PURE__ */ new Set(["warp", "list", "time"]);
@@ -6943,6 +7131,97 @@ function writeAdjustmentBlock(kind, params) {
6943
7131
  throw new Error(`Unknown adjustment kind "${kind}".`);
6944
7132
  }
6945
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
+
6946
7225
  // src/image-editor/psd/paths.ts
6947
7226
  var RECORD = 26;
6948
7227
  var fixed = (v) => v / 16777216;
@@ -8127,192 +8406,6 @@ function tyShForLayer(layer) {
8127
8406
  return writeTySh({ transform: textMatrix(layer), text: text3, warp, tail: new Uint8Array(16) });
8128
8407
  }
8129
8408
 
8130
- // src/image-editor/psd/compression.ts
8131
- var MAX_DECODED_BYTES = 2 ** 31;
8132
- function rowBytes(width, depth) {
8133
- return depth === 1 ? Math.ceil(width / 8) : width * Math.max(1, depth >> 3);
8134
- }
8135
- function decodedLength(l) {
8136
- const total = l.planes * l.height * rowBytes(l.width, l.depth);
8137
- if (total > MAX_DECODED_BYTES) throw new PsdError(`Decoded channel data of ${total} bytes is larger than the ${MAX_DECODED_BYTES}-byte limit.`);
8138
- return total;
8139
- }
8140
- function packbitsBound(n) {
8141
- return n + Math.ceil(n / 128);
8142
- }
8143
- function packbitsEncode(src, out, at) {
8144
- const n = src.length;
8145
- let i = 0;
8146
- while (i < n) {
8147
- let run = 1;
8148
- while (i + run < n && run < 128 && src[i + run] === src[i]) run++;
8149
- if (run >= 2) {
8150
- out[at++] = 257 - run & 255;
8151
- out[at++] = src[i];
8152
- i += run;
8153
- continue;
8154
- }
8155
- const start = i;
8156
- let len = 0;
8157
- while (i < n && len < 128) {
8158
- if (i + 2 < n && src[i] === src[i + 1] && src[i] === src[i + 2]) break;
8159
- i++;
8160
- len++;
8161
- }
8162
- out[at++] = len - 1;
8163
- out.set(src.subarray(start, start + len), at);
8164
- at += len;
8165
- }
8166
- return at;
8167
- }
8168
- function packbitsDecodeInto(src, expected, out, at) {
8169
- const target = at + expected;
8170
- let i = 0;
8171
- while (at < target) {
8172
- if (i >= src.length) throw new PsdError("PackBits row ended early.");
8173
- const h = src[i++];
8174
- if (h < 128) {
8175
- const len = h + 1;
8176
- if (i + len > src.length) throw new PsdError("PackBits literal is truncated.");
8177
- if (at + len > target) throw new PsdError("PackBits literal overflows its row.");
8178
- out.set(src.subarray(i, i + len), at);
8179
- at += len;
8180
- i += len;
8181
- } else if (h !== 128) {
8182
- const len = 257 - h;
8183
- if (i >= src.length) throw new PsdError("PackBits run is truncated.");
8184
- const b = src[i++];
8185
- if (at + len > target) throw new PsdError("PackBits run overflows its row.");
8186
- out.fill(b, at, at + len);
8187
- at += len;
8188
- }
8189
- }
8190
- return at;
8191
- }
8192
- function inflateChecked(data, expected) {
8193
- let out;
8194
- try {
8195
- out = inflate(data, { maxOutput: expected + (1 << 20), sizeHint: expected, verify: false });
8196
- } catch (e) {
8197
- throw new PsdError(`ZIP channel data: ${e instanceof ZlibError || e instanceof Error ? e.message : String(e)}`);
8198
- }
8199
- if (out.length < expected) throw new PsdError(`ZIP stream produced ${out.length} of ${expected} bytes.`);
8200
- return out.length === expected ? out : out.subarray(0, expected);
8201
- }
8202
- function unpredict(buf, l) {
8203
- const rb = rowBytes(l.width, l.depth);
8204
- if (rb === 0) return;
8205
- const w = l.width;
8206
- const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
8207
- for (let o = 0; o + rb <= buf.length; o += rb) {
8208
- if (l.depth === 1 || l.depth === 8) {
8209
- for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
8210
- } else if (l.depth === 16) {
8211
- for (let i = 1; i < w; i++) {
8212
- const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
8213
- const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
8214
- const v = a + b & 65535;
8215
- buf[o + 2 * i] = v >> 8;
8216
- buf[o + 2 * i + 1] = v & 255;
8217
- }
8218
- } else if (l.depth === 32) {
8219
- for (let i = 1; i < rb; i++) buf[o + i] = buf[o + i] + buf[o + i - 1] & 255;
8220
- scratch.set(buf.subarray(o, o + rb));
8221
- for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + 4 * i + k] = scratch[k * w + i];
8222
- } else {
8223
- throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
8224
- }
8225
- }
8226
- }
8227
- function decodeRle(r, l, total) {
8228
- const rows = l.planes * l.height;
8229
- const rb = rowBytes(l.width, l.depth);
8230
- r.checkCount(rows, l.psb ? 4 : 2, "RLE row counts");
8231
- const counts = new Array(rows);
8232
- for (let i = 0; i < rows; i++) counts[i] = l.psb ? r.u32() : r.u16();
8233
- if (total > r.remaining * 130) throw new PsdError("RLE data is too short for its declared size.");
8234
- const out = new Uint8Array(total);
8235
- let at = 0;
8236
- for (const c of counts) at = packbitsDecodeInto(r.bytes(c), rb, out, at);
8237
- return out;
8238
- }
8239
- function decodePlanes(compression, data, l) {
8240
- const total = decodedLength(l);
8241
- switch (compression) {
8242
- case 0:
8243
- if (data.length < total) throw new PsdError(`Raw channel data has ${data.length} of ${total} bytes.`);
8244
- return data.slice(0, total);
8245
- case 1:
8246
- return decodeRle(new PsdReader(data), l, total);
8247
- case 2:
8248
- return inflateChecked(data, total).slice();
8249
- case 3: {
8250
- const v = inflateChecked(data, total).slice();
8251
- unpredict(v, l);
8252
- return v;
8253
- }
8254
- default:
8255
- throw new PsdError(`Unsupported compression method ${compression}.`);
8256
- }
8257
- }
8258
- function encodeRle(decoded2, l) {
8259
- const rows = l.planes * l.height;
8260
- const rb = rowBytes(l.width, l.depth);
8261
- const cs = l.psb ? 4 : 2;
8262
- const packed = new Uint8Array(rows * packbitsBound(rb));
8263
- let at = 0;
8264
- const counts = new Uint8Array(rows * cs);
8265
- for (let row = 0; row < rows; row++) {
8266
- const start = at;
8267
- at = packbitsEncode(decoded2.subarray(row * rb, (row + 1) * rb), packed, at);
8268
- const n = at - start;
8269
- if (cs === 2) {
8270
- if (n > 65535) throw new PsdError("An RLE row is longer than 65535 bytes; write a PSB instead.");
8271
- counts[row * 2] = n >> 8;
8272
- counts[row * 2 + 1] = n & 255;
8273
- } else {
8274
- counts[row * 4] = n >>> 24;
8275
- counts[row * 4 + 1] = n >>> 16 & 255;
8276
- counts[row * 4 + 2] = n >>> 8 & 255;
8277
- counts[row * 4 + 3] = n & 255;
8278
- }
8279
- }
8280
- const out = new Uint8Array(counts.length + at);
8281
- out.set(counts);
8282
- out.set(packed.subarray(0, at), counts.length);
8283
- return out;
8284
- }
8285
- function predict(buf, l) {
8286
- const rb = rowBytes(l.width, l.depth);
8287
- if (rb === 0) return;
8288
- const w = l.width;
8289
- const scratch = l.depth === 32 ? new Uint8Array(rb) : null;
8290
- for (let o = 0; o + rb <= buf.length; o += rb) {
8291
- if (l.depth === 1 || l.depth === 8) {
8292
- for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
8293
- } else if (l.depth === 16) {
8294
- for (let i = w - 1; i > 0; i--) {
8295
- const a = buf[o + 2 * i] << 8 | buf[o + 2 * i + 1];
8296
- const b = buf[o + 2 * i - 2] << 8 | buf[o + 2 * i - 1];
8297
- const v = a - b & 65535;
8298
- buf[o + 2 * i] = v >> 8;
8299
- buf[o + 2 * i + 1] = v & 255;
8300
- }
8301
- } else if (l.depth === 32) {
8302
- scratch.set(buf.subarray(o, o + rb));
8303
- for (let i = 0; i < w; i++) for (let k = 0; k < 4; k++) buf[o + k * w + i] = scratch[4 * i + k];
8304
- for (let i = rb - 1; i > 0; i--) buf[o + i] = buf[o + i] - buf[o + i - 1] & 255;
8305
- } else {
8306
- throw new PsdError(`ZIP prediction is not defined for depth ${l.depth}.`);
8307
- }
8308
- }
8309
- }
8310
- function encodeZipPredicted(decoded2, l) {
8311
- const buf = decoded2.slice();
8312
- predict(buf, l);
8313
- return deflate(buf);
8314
- }
8315
-
8316
8409
  // src/image-editor/psd/smart.ts
8317
8410
  var dbl2 = (value) => ({ type: "doub", value });
8318
8411
  var unit2 = (u, value) => ({ type: "UntF", unit: u, value });
@@ -10359,6 +10452,16 @@ function psdToLayers(file, options = {}) {
10359
10452
  const bg = mergedLayer(ctx);
10360
10453
  if (bg) layers = [bg];
10361
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
+ }
10362
10465
  const i32 = (b) => b && b.length >= 4 ? new DataView(b.buffer, b.byteOffset, 4).getInt32(0) : void 0;
10363
10466
  const angle = i32(resource(file, 1037));
10364
10467
  const altitude = i32(resource(file, 1049));
@@ -10372,6 +10475,7 @@ function psdToLayers(file, options = {}) {
10372
10475
  patterns: [...ctx.patterns.values()],
10373
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)) } } : {},
10374
10477
  info: { psb: header.psb, depth: header.depth, colorMode: mode, channels: header.channels },
10478
+ ...alphaChannels.length ? { alphaChannels } : {},
10375
10479
  ...cmykProfile ? { sourceMode: { mode: "cmyk", profile: cmykProfile } } : header.colorMode === MODE_LAB ? { sourceMode: { mode: "lab" } } : {},
10376
10480
  ...resource(file, 1039) ? { iccProfile: resource(file, 1039).slice() } : {},
10377
10481
  bitDepth: (header.depth === 16 || header.depth === 32) && header.colorMode !== MODE_INDEXED && header.colorMode !== MODE_BITMAP ? header.depth : 8
@@ -11409,6 +11513,10 @@ function exportPsd(input) {
11409
11513
  planes = transparent ? dp : dp.slice(0, 3);
11410
11514
  }
11411
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
+ }
11412
11520
  const planeBytes = n * (depth >> 3);
11413
11521
  const merged2 = new Uint8Array(planeBytes * planes.length);
11414
11522
  planes.forEach((p, i) => merged2.set(p, i * planeBytes));
@@ -11430,6 +11538,7 @@ function exportPsd(input) {
11430
11538
  { id: 1057, name: "", data: version.result() }
11431
11539
  ];
11432
11540
  if (input.iccProfile?.length) resources.push({ id: 1039, name: "", data: input.iccProfile });
11541
+ resources.push(...alphaChannelResources(input.alphaChannels ?? []));
11433
11542
  if (input.globalLight) {
11434
11543
  const i32 = (v) => {
11435
11544
  const w = new PsdWriter();
@@ -11818,6 +11927,8 @@ export {
11818
11927
  deserializeLayer,
11819
11928
  deserializeLayers,
11820
11929
  PsdError,
11930
+ decodePlanes,
11931
+ encodeRle,
11821
11932
  parseVersionedDescriptor,
11822
11933
  versionedDescriptorBytes,
11823
11934
  ADJUSTMENT_KEYS,
@@ -11827,8 +11938,6 @@ export {
11827
11938
  parseLfx2,
11828
11939
  writeLfx2,
11829
11940
  parseLrfx,
11830
- decodePlanes,
11831
- encodeRle,
11832
11941
  BROWSER_IMAGE_TYPES,
11833
11942
  readPsd,
11834
11943
  layerName,