@poe-platform/safe-bash 0.1.787 → 0.1.789

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 (199) hide show
  1. package/README.md +1 -1
  2. package/dist/safe-bash/chunks/{chunk-WHURJBET.js → chunk-2MUJ7RLZ.js} +1 -1
  3. package/dist/safe-bash/chunks/{chunk-PYTLIUST.js → chunk-CTUHLNJM.js} +2 -2
  4. package/dist/safe-bash/chunks/{chunk-Z3HX3ZBA.js → chunk-D4PHJK4T.js} +1 -1
  5. package/dist/safe-bash/chunks/{chunk-O6356Z27.js → chunk-H7MMJS26.js} +2 -2
  6. package/dist/safe-bash/chunks/{chunk-Q3E6C3DX.js → chunk-KHJGUF2W.js} +14 -0
  7. package/dist/safe-bash/chunks/{chunk-FJZNUUOQ.js → chunk-VUVKC6HV.js} +1 -1
  8. package/dist/safe-bash/chunks/{chunk-ZMYVCRAF.js → chunk-X5ZCECM6.js} +2 -2
  9. package/dist/safe-bash/chunks/{git-UFNPAOYZ.js → git-HO7WDPHZ.js} +2 -2
  10. package/dist/safe-bash/command-chunks/{chunk-PFBJR2PY.js → chunk-2KRKKW5S.js} +2 -2
  11. package/dist/safe-bash/command-chunks/{chunk-4DSJDVBM.js → chunk-32F3RBUW.js} +10 -749
  12. package/dist/safe-bash/command-chunks/{chunk-WVWWRMFD.js → chunk-3KROFHBT.js} +1 -1
  13. package/dist/safe-bash/command-chunks/{chunk-L3MLMXL4.js → chunk-3ZK5F23O.js} +1 -1
  14. package/dist/safe-bash/command-chunks/{chunk-4QX6XCDD.js → chunk-4RNIZ3RT.js} +79 -0
  15. package/dist/safe-bash/command-chunks/{chunk-IFUNAM4D.js → chunk-5L62A5RO.js} +1 -1
  16. package/dist/safe-bash/command-chunks/{chunk-D7TADAYG.js → chunk-64LG3EVJ.js} +17 -0
  17. package/dist/safe-bash/command-chunks/{chunk-JUDOV5MJ.js → chunk-6F7QJMJ3.js} +1 -1
  18. package/dist/safe-bash/command-chunks/{chunk-IJ3FXP4Q.js → chunk-A3ZX6SCY.js} +1 -1
  19. package/dist/safe-bash/command-chunks/{chunk-DREUDEQG.js → chunk-AT6ZSOE6.js} +3 -3
  20. package/dist/safe-bash/command-chunks/{chunk-BUKYQBXO.js → chunk-BJ6DGYJA.js} +12 -12
  21. package/dist/safe-bash/command-chunks/{chunk-KSIGF4AG.js → chunk-BK4CMEE6.js} +1 -1
  22. package/dist/safe-bash/command-chunks/{chunk-NSEUBSOD.js → chunk-CXMOCPPH.js} +2 -2
  23. package/dist/safe-bash/command-chunks/{chunk-XGMWWUHV.js → chunk-CZ5DAK4K.js} +1 -1
  24. package/dist/safe-bash/command-chunks/{chunk-Z57TV6TC.js → chunk-EZ2DTOLI.js} +4 -2
  25. package/dist/safe-bash/command-chunks/{chunk-ADCGH6A7.js → chunk-FH3D75FC.js} +1 -1
  26. package/dist/safe-bash/command-chunks/{chunk-WYJTWJZ5.js → chunk-G3G6W5ZE.js} +1 -1
  27. package/dist/safe-bash/command-chunks/{chunk-3HDIDEUJ.js → chunk-GF54KE2M.js} +1 -1
  28. package/dist/safe-bash/command-chunks/{chunk-3JS4FOLB.js → chunk-HETU7MYN.js} +1 -1
  29. package/dist/safe-bash/command-chunks/{chunk-Z7TYZG3A.js → chunk-IHHTTQX6.js} +5 -3
  30. package/dist/safe-bash/command-chunks/{chunk-INDIFLBW.js → chunk-JTAGNROA.js} +4 -0
  31. package/dist/safe-bash/command-chunks/{chunk-Z47EO74H.js → chunk-MYKK3Q5G.js} +1 -1
  32. package/dist/safe-bash/command-chunks/{chunk-GZOUGVVV.js → chunk-OYZ534IK.js} +1 -1
  33. package/dist/safe-bash/command-chunks/chunk-PGEYORBZ.js +25 -0
  34. package/dist/safe-bash/command-chunks/chunk-QM4UZF3C.js +753 -0
  35. package/dist/safe-bash/command-chunks/{chunk-TOSM3T3A.js → chunk-UJOO6DKY.js} +20 -9
  36. package/dist/safe-bash/command-chunks/{chunk-TFZEYNMX.js → chunk-VQLFJCG7.js} +1 -1
  37. package/dist/safe-bash/command-chunks/{chunk-BIXN77VL.js → chunk-VUG324ER.js} +10 -0
  38. package/dist/safe-bash/command-chunks/{chunk-2LP3VMPA.js → chunk-WFDW4XXD.js} +1 -17
  39. package/dist/safe-bash/command-chunks/chunk-WR37IS4O.js +318 -0
  40. package/dist/safe-bash/command-chunks/{chunk-Y5IHIAY3.js → chunk-XNHSCU6I.js} +7 -3
  41. package/dist/safe-bash/commands/basic.js +148 -48
  42. package/dist/safe-bash/commands/bytes/compression/index.js +5 -6
  43. package/dist/safe-bash/commands/cmp.d.ts +2 -3
  44. package/dist/safe-bash/commands/cmp.js +2 -689
  45. package/dist/safe-bash/commands/docx/index.browser.js +3 -46
  46. package/dist/safe-bash/commands/docx/index.d.ts +2 -24
  47. package/dist/safe-bash/commands/docx/index.js +2 -41
  48. package/dist/safe-bash/commands/docx/io.d.ts +1 -14
  49. package/dist/safe-bash/commands/docx/io.js +1 -15
  50. package/dist/safe-bash/commands/llm/index.browser.js +3 -3
  51. package/dist/safe-bash/commands/network/index.browser.js +3 -3
  52. package/dist/safe-bash/commands/node/index.browser.js +3 -3
  53. package/dist/safe-bash/commands/pptx/index.d.ts +2 -28
  54. package/dist/safe-bash/commands/pptx/index.js +2 -152
  55. package/dist/safe-bash/commands/printf-float.d.ts +1 -0
  56. package/dist/safe-bash/commands/printf-float.js +48 -38
  57. package/dist/safe-bash/commands/printf-format.js +9 -6
  58. package/dist/safe-bash/commands/printf-quote.d.ts +3 -0
  59. package/dist/safe-bash/commands/printf-quote.js +62 -0
  60. package/dist/safe-bash/commands/printf-wide.d.ts +5 -0
  61. package/dist/safe-bash/commands/printf-wide.js +41 -0
  62. package/dist/safe-bash/commands/python/index.browser.js +2 -2
  63. package/dist/safe-bash/commands/truncate.d.ts +2 -3
  64. package/dist/safe-bash/commands/truncate.js +2 -686
  65. package/dist/safe-bash/contracts/diagnostics.d.ts +2 -0
  66. package/dist/safe-bash/contracts/diagnostics.js +2 -0
  67. package/dist/safe-bash/contracts/runtime-control.d.ts +2 -0
  68. package/dist/safe-bash/contracts/runtime-control.js +2 -0
  69. package/dist/safe-bash/core.browser.d.ts +1 -1
  70. package/dist/safe-bash/core.browser.js +2651 -4871
  71. package/dist/safe-bash/core.d.ts +10 -0
  72. package/dist/safe-bash/opt-in/commands/cmp/index.d.ts +6 -2
  73. package/dist/safe-bash/opt-in/commands/cmp/index.js +776 -79
  74. package/dist/safe-bash/opt-in/commands/cmp/options.d.ts +0 -12
  75. package/dist/safe-bash/opt-in/commands/cmp/options.js +0 -153
  76. package/dist/safe-bash/opt-in/commands/truncate/index.d.ts +8 -3
  77. package/dist/safe-bash/opt-in/commands/truncate/index.js +790 -272
  78. package/dist/safe-bash/opt-in/commands/truncate/sync.d.ts +1 -0
  79. package/dist/safe-bash/opt-in/commands/truncate/sync.js +60 -0
  80. package/dist/safe-bash/optional-host.browser.js +9 -1
  81. package/dist/safe-bash/optional-host.d.ts +3 -1
  82. package/dist/safe-bash/optional-host.js +3 -1
  83. package/dist/safe-bash/shell/runtime.js +10 -6
  84. package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
  85. package/dist/safe-bash-checksum-engine/index.js +14 -2
  86. package/dist/safe-bash-command-bzip2/index.js +2 -1
  87. package/dist/safe-bash-command-cmp/index.d.ts +10 -0
  88. package/dist/safe-bash-command-cmp/index.js +796 -0
  89. package/dist/safe-bash-command-cmp/options.d.ts +12 -0
  90. package/dist/safe-bash-command-cmp/options.js +42 -0
  91. package/dist/safe-bash-command-csvcut/index.js +11 -8
  92. package/dist/safe-bash-command-csvgrep/index.js +35 -7
  93. package/dist/safe-bash-command-csvkit/codecs/python.js +4 -3
  94. package/dist/safe-bash-command-csvkit/codecs/utf8.js +3 -2
  95. package/dist/safe-bash-command-csvkit/index.js +80 -324
  96. package/dist/safe-bash-command-csvkit/python-regex.d.ts +5 -0
  97. package/dist/safe-bash-command-csvkit/python-regex.js +14 -0
  98. package/dist/safe-bash-command-csvkit/runtime.d.ts +1 -0
  99. package/dist/safe-bash-command-csvkit/sync-support.js +4 -2
  100. package/dist/safe-bash-command-diff3/index.js +3 -0
  101. package/dist/safe-bash-command-docx/LICENSE +21 -0
  102. package/dist/safe-bash-command-docx/index.d.ts +30 -0
  103. package/dist/safe-bash-command-docx/index.js +67 -0
  104. package/dist/safe-bash-command-docx/io.d.ts +14 -0
  105. package/dist/safe-bash-command-docx/io.js +26 -0
  106. package/dist/safe-bash-command-envsubst/index.js +34 -3
  107. package/dist/safe-bash-command-exiftool/index.js +3 -0
  108. package/dist/safe-bash-command-ffmpeg/index.js +1102 -1088
  109. package/dist/safe-bash-command-fold/family.js +1 -1
  110. package/dist/safe-bash-command-fold/index.js +1 -1
  111. package/dist/safe-bash-command-htmlq/index.js +5 -0
  112. package/dist/safe-bash-command-imagemagick/index.d.ts +25 -21
  113. package/dist/safe-bash-command-imagemagick/index.js +669 -271
  114. package/dist/safe-bash-command-mmdc/index.js +48 -10
  115. package/dist/safe-bash-command-mmdc/svg.d.ts +1 -0
  116. package/dist/safe-bash-command-op/index.js +19 -14
  117. package/dist/safe-bash-command-pandoc/command.js +1 -1
  118. package/dist/safe-bash-command-pandoc/index.js +1 -1
  119. package/dist/safe-bash-command-pdfimages/index.d.ts +7 -1
  120. package/dist/safe-bash-command-pdfimages/index.js +63 -33
  121. package/dist/safe-bash-command-pdfinfo/index.d.ts +24 -20
  122. package/dist/safe-bash-command-pdfinfo/index.js +370 -161
  123. package/dist/safe-bash-command-pdftk/index.d.ts +7 -3
  124. package/dist/safe-bash-command-pdftk/index.js +114 -45
  125. package/dist/safe-bash-command-pdftoppm/index.d.ts +15 -7
  126. package/dist/safe-bash-command-pdftoppm/index.js +179 -109
  127. package/dist/safe-bash-command-pdftotext/index.d.ts +9 -5
  128. package/dist/safe-bash-command-pdftotext/index.js +90 -27
  129. package/dist/safe-bash-command-pptx/LICENSE +21 -0
  130. package/dist/safe-bash-command-pptx/index.d.ts +33 -0
  131. package/dist/safe-bash-command-pptx/index.js +168 -0
  132. package/dist/safe-bash-command-qpdf/index.d.ts +9 -3
  133. package/dist/safe-bash-command-qpdf/index.js +80 -29
  134. package/dist/safe-bash-command-sha512sum/index.js +12 -475
  135. package/dist/safe-bash-command-sips/index.d.ts +9 -5
  136. package/dist/safe-bash-command-sips/index.js +63 -44
  137. package/dist/safe-bash-command-soffice/index.d.ts +9 -3
  138. package/dist/safe-bash-command-soffice/index.js +65 -24
  139. package/dist/safe-bash-command-sqlite3/engine.d.ts +9 -0
  140. package/dist/safe-bash-command-sqlite3/index.d.ts +1 -0
  141. package/dist/safe-bash-command-sqlite3/index.js +851 -352
  142. package/dist/safe-bash-command-ssconvert/formats/xls.js +3 -3
  143. package/dist/safe-bash-command-timeout/index.js +3 -3
  144. package/dist/safe-bash-command-truncate/index.d.ts +8 -3
  145. package/dist/safe-bash-command-truncate/index.js +790 -272
  146. package/dist/safe-bash-command-truncate/sync.d.ts +1 -0
  147. package/dist/safe-bash-command-truncate/sync.js +60 -0
  148. package/dist/safe-bash-command-wkhtmltopdf/index.js +92 -38
  149. package/dist/safe-bash-command-wkhtmltopdf/pdf-renderer.d.ts +1 -1
  150. package/dist/safe-bash-command-xxd/index.js +78 -20
  151. package/dist/safe-bash-command-xz/command.d.ts +4 -0
  152. package/dist/safe-bash-command-xz/index.d.ts +1 -1
  153. package/dist/safe-bash-command-xz/index.js +1 -1
  154. package/dist/safe-bash-compression-engine/bounded-codec.js +3 -3
  155. package/dist/safe-bash-compression-engine/codec-loader.js +2 -2
  156. package/dist/safe-bash-compression-engine/files.js +6 -6
  157. package/dist/safe-bash-compression-engine/index.js +5 -5
  158. package/dist/safe-bash-compression-engine/operand.js +6 -6
  159. package/dist/safe-bash-compression-engine/stream.js +5 -5
  160. package/dist/safe-bash-compression-engine/zstd-decode.js +4 -4
  161. package/dist/safe-bash-contracts/command.js +3 -3
  162. package/dist/safe-bash-contracts/diagnostics.js +3 -3
  163. package/dist/safe-bash-contracts/escaping.js +9 -9
  164. package/dist/safe-bash-contracts/filesystem-descriptor.js +3 -3
  165. package/dist/safe-bash-contracts/filesystem-output.js +8 -8
  166. package/dist/safe-bash-contracts/index.js +21 -19
  167. package/dist/safe-bash-contracts/io.d.ts +12 -0
  168. package/dist/safe-bash-contracts/io.js +4 -1
  169. package/dist/safe-bash-contracts/output.js +3 -2
  170. package/dist/safe-bash-contracts/runtime-control.js +2 -2
  171. package/dist/safe-bash-contracts/signals.js +1 -1
  172. package/dist/safe-bash-contracts/yield.d.ts +1 -0
  173. package/dist/safe-bash-contracts/yield.js +3 -1
  174. package/dist/safe-bash-csv-engine/index.d.ts +10 -1
  175. package/dist/safe-bash-csv-engine/index.js +78 -6
  176. package/dist/safe-bash-io-engine/commands/search/requirements.js +3 -3
  177. package/dist/safe-bash-io-engine/commands/text-programs/shared.js +3 -3
  178. package/dist/safe-bash-io-engine/gnu-information.js +1 -1
  179. package/dist/safe-bash-io-engine/internal.d.ts +1 -1
  180. package/dist/safe-bash-io-engine/internal.js +2 -2
  181. package/dist/safe-bash-mcp/index.browser.d.ts +875 -0
  182. package/dist/safe-bash-mcp/index.browser.js +8740 -0
  183. package/dist/safe-bash-mcp/index.js +32 -31
  184. package/dist/safe-bash-query-engine/capture.js +3 -3
  185. package/dist/safe-bash-query-engine/delpaths.js +3 -3
  186. package/dist/safe-bash-query-engine/formats.js +2 -2
  187. package/dist/safe-bash-query-engine/index.js +12 -12
  188. package/dist/safe-bash-query-engine/indices.js +3 -3
  189. package/dist/safe-bash-query-engine/input.js +1 -1
  190. package/dist/safe-bash-query-engine/interpreter.js +10 -10
  191. package/dist/safe-bash-query-engine/query-core.js +12 -12
  192. package/dist/safe-bash-query-engine/regex.js +3 -3
  193. package/dist/safe-bash-query-engine/splits.js +4 -4
  194. package/dist/safe-bash-query-engine/values.js +2 -2
  195. package/package.json +9 -3
  196. package/dist/safe-bash/opt-in/commands/cmp/compare.js +0 -95
  197. package/dist/safe-bash/opt-in/commands/cmp/io.js +0 -218
  198. package/dist/safe-bash/command-chunks/{chunk-FXYWQ6S4.js → chunk-2VTMZTV3.js} +0 -0
  199. package/dist/safe-bash/command-chunks/{chunk-DEH3CMGL.js → chunk-QJ3ONEBI.js} +3 -3
@@ -36,6 +36,8 @@ import {
36
36
 
37
37
  // packages/safe-bash-command-imagemagick/dist/index.js
38
38
  init_buffer();
39
+ import { yieldTurn, drainCooperativeSteps as drainSteps } from "../safe-bash-contracts/yield.js";
40
+ import { InputByteBudget } from "../safe-bash-contracts/io.js";
39
41
  import { writeFileOutput } from "../safe-bash-contracts/filesystem-output-budget.js";
40
42
  import {
41
43
  commandRuntimeIdentity,
@@ -445,7 +447,8 @@ function createDefaultState() {
445
447
  channelExplicit: false
446
448
  };
447
449
  }
448
- function applyMagickMorphology4Ch(img, methodRaw, kernelSpec) {
450
+ function* applyMagickMorphology4ChSteps(img, methodRaw, kernelSpec, signal) {
451
+ let cooperativeWork = 0;
449
452
  const m = methodRaw.toLowerCase();
450
453
  let rx = 1;
451
454
  let ry = 1;
@@ -504,13 +507,23 @@ function applyMagickMorphology4Ch(img, methodRaw, kernelSpec) {
504
507
  const out = new Uint8Array(img.data.length);
505
508
  const win = [];
506
509
  for (let y = 0; y < h; y++) {
510
+ if (++cooperativeWork % 65536 === 0)
511
+ yield;
507
512
  for (let x = 0; x < w; x++) {
513
+ if (++cooperativeWork % 65536 === 0)
514
+ yield;
508
515
  const dstOff = (y * w + x) * 4;
509
516
  for (let c = 0; c < 4; c++) {
517
+ if (++cooperativeWork % 65536 === 0)
518
+ yield;
510
519
  win.length = 0;
511
520
  for (let dy = -ry; dy <= ry; dy++) {
521
+ if (++cooperativeWork % 65536 === 0)
522
+ yield;
512
523
  const sy = Math.max(0, Math.min(h - 1, y + dy));
513
524
  for (let dx = -rx; dx <= rx; dx++) {
525
+ if (++cooperativeWork % 65536 === 0)
526
+ yield;
514
527
  const sx = Math.max(0, Math.min(w - 1, x + dx));
515
528
  win.push(img.data[(sy * w + sx) * 4 + c]);
516
529
  }
@@ -552,7 +565,8 @@ function createRoseImage() {
552
565
  data
553
566
  };
554
567
  }
555
- function applyMagickFloodfill(img, geomStr, targetColor, replacement, fuzz) {
568
+ function* applyMagickFloodfillSteps(img, geomStr, targetColor, replacement, fuzz, signal) {
569
+ let cooperativeWork = 0;
556
570
  const g = parseMagickGeometry(geomStr);
557
571
  const w = img.width;
558
572
  const h = img.height;
@@ -580,6 +594,8 @@ function applyMagickFloodfill(img, geomStr, targetColor, replacement, fuzz) {
580
594
  queue[tail++] = startIdx;
581
595
  visited[startIdx] = 1;
582
596
  while (head < tail) {
597
+ if (++cooperativeWork % 65536 === 0)
598
+ yield;
583
599
  const cur = queue[head++];
584
600
  const off = cur * 4;
585
601
  out[off] = replacement.r;
@@ -595,6 +611,8 @@ function applyMagickFloodfill(img, geomStr, targetColor, replacement, fuzz) {
595
611
  cy + 1 < h ? cur + w : -1
596
612
  ];
597
613
  for (const nb of neighbors) {
614
+ if (++cooperativeWork % 65536 === 0)
615
+ yield;
598
616
  if (nb >= 0 && visited[nb] === 0 && matchesRef(nb)) {
599
617
  visited[nb] = 1;
600
618
  queue[tail++] = nb;
@@ -603,7 +621,8 @@ function applyMagickFloodfill(img, geomStr, targetColor, replacement, fuzz) {
603
621
  }
604
622
  return { ...img, data: out, hasAlpha: true };
605
623
  }
606
- function applyMagickEvaluateSequence(stack, opRaw) {
624
+ function* applyMagickEvaluateSequenceSteps(stack, opRaw, signal) {
625
+ let cooperativeWork = 0;
607
626
  if (stack.length === 0) {
608
627
  throw new Error("evaluate-sequence requires at least one image");
609
628
  }
@@ -611,25 +630,28 @@ function applyMagickEvaluateSequence(stack, opRaw) {
611
630
  const base = stack[0];
612
631
  const w = base.width;
613
632
  const h = base.height;
614
- const normalized = stack.map(
615
- (im) => im.width === w && im.height === h ? im : applyMagickResize(im, `${w}x${h}!`, "bilinear")
616
- );
633
+ const normalized = stack.map((im) => im.width === w && im.height === h ? im : applyMagickResize(im, `${w}x${h}!`, "bilinear"));
617
634
  const n = normalized.length;
618
635
  const out = new Uint8Array(w * h * 4);
619
636
  const op = opRaw.toLowerCase().replace(/[-_]/g, "");
620
637
  const vals = new Float64Array(n);
621
638
  for (let i = 0; i < out.length; i++) {
639
+ if (++cooperativeWork % 65536 === 0)
640
+ yield;
622
641
  if ((i & 3) === 3) {
623
642
  out[i] = base.data[i];
624
643
  continue;
625
644
  }
626
645
  for (let k = 0; k < n; k++) {
646
+ if (++cooperativeWork % 65536 === 0)
647
+ yield;
627
648
  vals[k] = normalized[k].data[i];
628
649
  }
629
650
  let res = vals[0];
630
651
  if (op === "mean" || op === "average") {
631
652
  let s = 0;
632
- for (let k = 0; k < n; k++) s += vals[k];
653
+ for (let k = 0; k < n; k++)
654
+ s += vals[k];
633
655
  res = s / n;
634
656
  } else if (op === "median") {
635
657
  const baseOff = i & ~3;
@@ -647,33 +669,47 @@ function applyMagickEvaluateSequence(stack, opRaw) {
647
669
  res = Math.max(...vals);
648
670
  } else if (op === "add") {
649
671
  let s = 0;
650
- for (let k = 0; k < n; k++) s += vals[k];
672
+ for (let k = 0; k < n; k++)
673
+ s += vals[k];
651
674
  res = s;
652
675
  } else if (op === "multiply") {
653
676
  let p = 1;
654
- for (let k = 0; k < n; k++) p *= vals[k] / 255;
677
+ for (let k = 0; k < n; k++)
678
+ p *= vals[k] / 255;
655
679
  res = p * 255;
656
680
  }
657
681
  out[i] = clampByteVal(res);
658
682
  }
659
683
  return { ...base, data: out };
660
684
  }
661
- function applyMagickCustomConvolve(img, spec) {
685
+ function* applyMagickCustomConvolveSteps(img, spec, signal) {
686
+ let cooperativeWork = 0;
662
687
  const afterColon = spec.includes(":") ? spec.slice(spec.indexOf(":") + 1) : spec;
663
688
  const coeffs = afterColon.trim().split(/[\s,]+/).filter((s) => s.length > 0).map(Number).filter((n) => Number.isFinite(n));
664
- if (coeffs.length === 0) return img;
689
+ if (coeffs.length === 0)
690
+ return img;
665
691
  const side = Math.max(1, Math.round(Math.sqrt(coeffs.length)));
666
692
  const half = Math.floor(side / 2);
667
693
  const w = img.width;
668
694
  const h = img.height;
669
695
  const out = new Uint8Array(img.data);
670
696
  for (let y = 0; y < h; y++) {
697
+ if (++cooperativeWork % 65536 === 0)
698
+ yield;
671
699
  for (let x = 0; x < w; x++) {
700
+ if (++cooperativeWork % 65536 === 0)
701
+ yield;
672
702
  for (let c = 0; c < 3; c++) {
703
+ if (++cooperativeWork % 65536 === 0)
704
+ yield;
673
705
  let sum = 0;
674
706
  for (let ky = 0; ky < side; ky++) {
707
+ if (++cooperativeWork % 65536 === 0)
708
+ yield;
675
709
  const sy = Math.max(0, Math.min(h - 1, y + ky - half));
676
710
  for (let kx = 0; kx < side; kx++) {
711
+ if (++cooperativeWork % 65536 === 0)
712
+ yield;
677
713
  const sx = Math.max(0, Math.min(w - 1, x + kx - half));
678
714
  const weight = coeffs[ky * side + kx] ?? 0;
679
715
  sum += img.data[(sy * w + sx) * 4 + c] * weight;
@@ -685,51 +721,66 @@ function applyMagickCustomConvolve(img, spec) {
685
721
  }
686
722
  return { ...img, data: out };
687
723
  }
688
- function applyMagickColorMatrix(img, spec) {
724
+ function* applyMagickColorMatrixSteps(img, spec, signal) {
725
+ let cooperativeWork = 0;
689
726
  const afterColon = spec.includes(":") ? spec.slice(spec.indexOf(":") + 1) : spec;
690
727
  const m = afterColon.trim().split(/[\s,]+/).filter((s) => s.length > 0).map(Number);
691
- if (m.length < 9) return img;
728
+ if (m.length < 9)
729
+ return img;
692
730
  const out = new Uint8Array(img.data);
693
731
  const cols = m.length >= 16 ? Math.round(Math.sqrt(m.length)) : 3;
694
732
  for (let i = 0; i < out.length; i += 4) {
733
+ if (++cooperativeWork % 65536 === 0)
734
+ yield;
695
735
  const r = out[i];
696
736
  const g = out[i + 1];
697
737
  const b = out[i + 2];
698
738
  out[i] = clampByteVal((m[0] ?? 1) * r + (m[1] ?? 0) * g + (m[2] ?? 0) * b);
699
739
  out[i + 1] = clampByteVal((m[cols] ?? 0) * r + (m[cols + 1] ?? 1) * g + (m[cols + 2] ?? 0) * b);
700
- out[i + 2] = clampByteVal(
701
- (m[cols * 2] ?? 0) * r + (m[cols * 2 + 1] ?? 0) * g + (m[cols * 2 + 2] ?? 1) * b
702
- );
740
+ out[i + 2] = clampByteVal((m[cols * 2] ?? 0) * r + (m[cols * 2 + 1] ?? 0) * g + (m[cols * 2 + 2] ?? 1) * b);
703
741
  }
704
742
  return { ...img, data: out };
705
743
  }
706
- function applyMagickEqualize(img) {
744
+ function* applyMagickEqualizeSteps(img, signal) {
745
+ let cooperativeWork = 0;
707
746
  const out = new Uint8Array(img.data);
708
747
  const totalPixels = Math.max(1, img.width * img.height);
709
748
  for (let c = 0; c < 3; c++) {
749
+ if (++cooperativeWork % 65536 === 0)
750
+ yield;
710
751
  const hist = new Uint32Array(256);
711
752
  for (let i = c; i < out.length; i += 4) {
753
+ if (++cooperativeWork % 65536 === 0)
754
+ yield;
712
755
  hist[out[i]]++;
713
756
  }
714
757
  const lut = new Uint8Array(256);
715
758
  let cdf = 0;
716
759
  let cdfMin = 0;
717
760
  for (let v = 0; v < 256; v++) {
761
+ if (++cooperativeWork % 65536 === 0)
762
+ yield;
718
763
  cdf += hist[v];
719
- if (cdfMin === 0 && cdf > 0) cdfMin = cdf;
764
+ if (cdfMin === 0 && cdf > 0)
765
+ cdfMin = cdf;
720
766
  const denom = Math.max(1, totalPixels - cdfMin);
721
767
  lut[v] = clampByteVal((cdf - cdfMin) / denom * 255);
722
768
  }
723
769
  for (let i = c; i < out.length; i += 4) {
770
+ if (++cooperativeWork % 65536 === 0)
771
+ yield;
724
772
  out[i] = lut[out[i]];
725
773
  }
726
774
  }
727
775
  return { ...img, data: out };
728
776
  }
729
- function applyMagickRemap(img, palImg, dither) {
777
+ function* applyMagickRemapSteps(img, palImg, dither, signal) {
778
+ let cooperativeWork = 0;
730
779
  const palette = [];
731
780
  const seen = /* @__PURE__ */ new Set();
732
781
  for (let i = 0; i < palImg.data.length; i += 4) {
782
+ if (++cooperativeWork % 65536 === 0)
783
+ yield;
733
784
  const r = palImg.data[i];
734
785
  const g = palImg.data[i + 1];
735
786
  const b = palImg.data[i + 2];
@@ -737,16 +788,22 @@ function applyMagickRemap(img, palImg, dither) {
737
788
  if (!seen.has(key)) {
738
789
  seen.add(key);
739
790
  palette.push({ r, g, b });
740
- if (palette.length >= 256) break;
791
+ if (palette.length >= 256)
792
+ break;
741
793
  }
742
794
  }
743
- if (palette.length === 0) return img;
795
+ if (palette.length === 0)
796
+ return img;
744
797
  const w = img.width;
745
798
  const h = img.height;
746
799
  const buf = new Float32Array(img.data);
747
800
  const out = new Uint8Array(img.data);
748
801
  for (let y = 0; y < h; y++) {
802
+ if (++cooperativeWork % 65536 === 0)
803
+ yield;
749
804
  for (let x = 0; x < w; x++) {
805
+ if (++cooperativeWork % 65536 === 0)
806
+ yield;
750
807
  const idx = (y * w + x) * 4;
751
808
  const oldR = Math.max(0, Math.min(255, buf[idx]));
752
809
  const oldG = Math.max(0, Math.min(255, buf[idx + 1]));
@@ -754,6 +811,8 @@ function applyMagickRemap(img, palImg, dither) {
754
811
  let best = palette[0];
755
812
  let bestDist = Infinity;
756
813
  for (const p of palette) {
814
+ if (++cooperativeWork % 65536 === 0)
815
+ yield;
757
816
  const d = (oldR - p.r) ** 2 + (oldG - p.g) ** 2 + (oldB - p.b) ** 2;
758
817
  if (d < bestDist) {
759
818
  bestDist = d;
@@ -768,7 +827,8 @@ function applyMagickRemap(img, palImg, dither) {
768
827
  const errG = oldG - best.g;
769
828
  const errB = oldB - best.b;
770
829
  const spread = (nx, ny, wgt) => {
771
- if (nx < 0 || nx >= w || ny < 0 || ny >= h) return;
830
+ if (nx < 0 || nx >= w || ny < 0 || ny >= h)
831
+ return;
772
832
  const nIdx = (ny * w + nx) * 4;
773
833
  buf[nIdx] = buf[nIdx] + errR * wgt;
774
834
  buf[nIdx + 1] = buf[nIdx + 1] + errG * wgt;
@@ -909,7 +969,8 @@ function createCheckerboardImage(width, height) {
909
969
  data
910
970
  };
911
971
  }
912
- function applyMagickSplice(img, geomStr, bg, gravity = "northwest") {
972
+ function* applyMagickSpliceSteps(img, geomStr, bg, gravity = "northwest", signal) {
973
+ let cooperativeWork = 0;
913
974
  const g = parseMagickGeometry(geomStr);
914
975
  const sw = Math.max(0, Math.round(g.width ?? 0));
915
976
  const sh = Math.max(0, Math.round(g.height ?? 0));
@@ -922,7 +983,11 @@ function applyMagickSplice(img, geomStr, bg, gravity = "northwest") {
922
983
  const outH = img.height + sh;
923
984
  const out = new Uint8Array(outW * outH * 4);
924
985
  for (let y = 0; y < outH; y++) {
986
+ if (++cooperativeWork % 65536 === 0)
987
+ yield;
925
988
  for (let x = 0; x < outW; x++) {
989
+ if (++cooperativeWork % 65536 === 0)
990
+ yield;
926
991
  const dstIdx = (y * outW + x) * 4;
927
992
  if (x >= sx && x < sx + sw || y >= sy && y < sy + sh) {
928
993
  out[dstIdx] = bg.r;
@@ -942,7 +1007,8 @@ function applyMagickSplice(img, geomStr, bg, gravity = "northwest") {
942
1007
  }
943
1008
  return { ...img, width: outW, height: outH, data: out, hasAlpha: true };
944
1009
  }
945
- function applyMagickChop(img, geomStr, gravity = "northwest") {
1010
+ function* applyMagickChopSteps(img, geomStr, gravity = "northwest", signal) {
1011
+ let cooperativeWork = 0;
946
1012
  const g = parseMagickGeometry(geomStr);
947
1013
  const cw = Math.max(0, Math.round(g.width ?? 0));
948
1014
  const ch = Math.max(0, Math.round(g.height ?? 0));
@@ -963,8 +1029,12 @@ function applyMagickChop(img, geomStr, gravity = "northwest") {
963
1029
  const outH = img.height - choppedH;
964
1030
  const out = new Uint8Array(outW * outH * 4);
965
1031
  for (let y = 0; y < outH; y++) {
1032
+ if (++cooperativeWork % 65536 === 0)
1033
+ yield;
966
1034
  const srcY = y < cy0 ? y : Math.min(img.height - 1, y + choppedH);
967
1035
  for (let x = 0; x < outW; x++) {
1036
+ if (++cooperativeWork % 65536 === 0)
1037
+ yield;
968
1038
  const srcX = x < cx0 ? x : Math.min(img.width - 1, x + choppedW);
969
1039
  const dstIdx = (y * outW + x) * 4;
970
1040
  const srcIdx = (srcY * img.width + srcX) * 4;
@@ -976,7 +1046,8 @@ function applyMagickChop(img, geomStr, gravity = "northwest") {
976
1046
  }
977
1047
  return { ...img, width: outW, height: outH, data: out };
978
1048
  }
979
- function applyMagickRoll(img, geomStr) {
1049
+ function* applyMagickRollSteps(img, geomStr, signal) {
1050
+ let cooperativeWork = 0;
980
1051
  const g = parseMagickGeometry(geomStr);
981
1052
  const rx = Math.round(g.x || g.width || 0);
982
1053
  const ry = Math.round(g.y || g.height || 0);
@@ -984,8 +1055,12 @@ function applyMagickRoll(img, geomStr) {
984
1055
  const h = img.height;
985
1056
  const out = new Uint8Array(img.data.length);
986
1057
  for (let y = 0; y < h; y++) {
1058
+ if (++cooperativeWork % 65536 === 0)
1059
+ yield;
987
1060
  const sy = ((y - ry) % h + h) % h;
988
1061
  for (let x = 0; x < w; x++) {
1062
+ if (++cooperativeWork % 65536 === 0)
1063
+ yield;
989
1064
  const sx = ((x - rx) % w + w) % w;
990
1065
  const dstIdx = (y * w + x) * 4;
991
1066
  const srcIdx = (sy * w + sx) * 4;
@@ -997,15 +1072,21 @@ function applyMagickRoll(img, geomStr) {
997
1072
  }
998
1073
  return { ...img, data: out };
999
1074
  }
1000
- function applyMagickMorph(stack, countRaw) {
1075
+ function* applyMagickMorphSteps(stack, countRaw, signal) {
1076
+ let cooperativeWork = 0;
1001
1077
  const count = Math.max(0, Math.round(countRaw));
1002
- if (stack.length < 2 || count === 0) return [...stack];
1078
+ if (stack.length < 2 || count === 0)
1079
+ return [...stack];
1003
1080
  const out = [];
1004
1081
  for (let idx = 0; idx < stack.length - 1; idx++) {
1082
+ if (++cooperativeWork % 65536 === 0)
1083
+ yield;
1005
1084
  const a = stack[idx];
1006
1085
  const b = stack[idx + 1];
1007
1086
  out.push(a);
1008
1087
  for (let step = 1; step <= count; step++) {
1088
+ if (++cooperativeWork % 65536 === 0)
1089
+ yield;
1009
1090
  const t = step / (count + 1);
1010
1091
  const w = Math.max(1, Math.round(a.width * (1 - t) + b.width * t));
1011
1092
  const h = Math.max(1, Math.round(a.height * (1 - t) + b.height * t));
@@ -1013,6 +1094,8 @@ function applyMagickMorph(stack, countRaw) {
1013
1094
  const rb = b.width === w && b.height === h ? b : applyMagickResize(b, `${w}x${h}!`, "bilinear");
1014
1095
  const data = new Uint8Array(w * h * 4);
1015
1096
  for (let p = 0; p < data.length; p++) {
1097
+ if (++cooperativeWork % 65536 === 0)
1098
+ yield;
1016
1099
  data[p] = clampByteVal(ra.data[p] * (1 - t) + rb.data[p] * t);
1017
1100
  }
1018
1101
  out.push({ ...ra, width: w, height: h, data });
@@ -1060,9 +1143,12 @@ function clampByteVal(n) {
1060
1143
  if (!Number.isFinite(n)) return 0;
1061
1144
  return Math.max(0, Math.min(255, Math.round(n)));
1062
1145
  }
1063
- function applyMagickOpaque(img, target, replacement, fuzz, invert) {
1146
+ function* applyMagickOpaqueSteps(img, target, replacement, fuzz, invert, signal) {
1147
+ let cooperativeWork = 0;
1064
1148
  const out = new Uint8Array(img.data);
1065
1149
  for (let i = 0; i < out.length; i += 4) {
1150
+ if (++cooperativeWork % 65536 === 0)
1151
+ yield;
1066
1152
  const dr = Math.abs(out[i] - target.r);
1067
1153
  const dg = Math.abs(out[i + 1] - target.g);
1068
1154
  const db = Math.abs(out[i + 2] - target.b);
@@ -1076,9 +1162,12 @@ function applyMagickOpaque(img, target, replacement, fuzz, invert) {
1076
1162
  }
1077
1163
  return { ...img, data: out, hasAlpha: true };
1078
1164
  }
1079
- function applyMagickTransparent(img, target, fuzz, invert) {
1165
+ function* applyMagickTransparentSteps(img, target, fuzz, invert, signal) {
1166
+ let cooperativeWork = 0;
1080
1167
  const out = new Uint8Array(img.data);
1081
1168
  for (let i = 0; i < out.length; i += 4) {
1169
+ if (++cooperativeWork % 65536 === 0)
1170
+ yield;
1082
1171
  const dr = Math.abs(out[i] - target.r);
1083
1172
  const dg = Math.abs(out[i + 1] - target.g);
1084
1173
  const db = Math.abs(out[i + 2] - target.b);
@@ -1089,7 +1178,8 @@ function applyMagickTransparent(img, target, fuzz, invert) {
1089
1178
  }
1090
1179
  return { ...img, data: out, hasAlpha: true };
1091
1180
  }
1092
- function applyMagickEvaluate(img, opRaw, valStr, channels) {
1181
+ function* applyMagickEvaluateSteps(img, opRaw, valStr, channels, signal) {
1182
+ let cooperativeWork = 0;
1093
1183
  const op = opRaw.toLowerCase().replace(/[-_]/g, "");
1094
1184
  const isPct = valStr.trim().endsWith("%");
1095
1185
  const rawNum = parseFloat(valStr);
@@ -1098,8 +1188,13 @@ function applyMagickEvaluate(img, opRaw, valStr, channels) {
1098
1188
  const out = new Uint8Array(img.data);
1099
1189
  const mask = [channels.r, channels.g, channels.b, channels.a];
1100
1190
  for (let i = 0; i < out.length; i += 4) {
1191
+ if (++cooperativeWork % 65536 === 0)
1192
+ yield;
1101
1193
  for (let c = 0; c < 4; c++) {
1102
- if (!mask[c]) continue;
1194
+ if (++cooperativeWork % 65536 === 0)
1195
+ yield;
1196
+ if (!mask[c])
1197
+ continue;
1103
1198
  const cur = out[i + c];
1104
1199
  let next = cur;
1105
1200
  switch (op) {
@@ -1177,14 +1272,20 @@ function applyMagickEvaluate(img, opRaw, valStr, channels) {
1177
1272
  }
1178
1273
  return { ...img, data: out };
1179
1274
  }
1180
- function applyMagickFunction(img, funcRaw, paramsRaw, channels) {
1275
+ function* applyMagickFunctionSteps(img, funcRaw, paramsRaw, channels, signal) {
1276
+ let cooperativeWork = 0;
1181
1277
  const fn = funcRaw.toLowerCase();
1182
1278
  const params = paramsRaw.split(",").map((s) => Number(s.trim()));
1183
1279
  const out = new Uint8Array(img.data);
1184
1280
  const mask = [channels.r, channels.g, channels.b, channels.a];
1185
1281
  for (let i = 0; i < out.length; i += 4) {
1282
+ if (++cooperativeWork % 65536 === 0)
1283
+ yield;
1186
1284
  for (let c = 0; c < 4; c++) {
1187
- if (!mask[c]) continue;
1285
+ if (++cooperativeWork % 65536 === 0)
1286
+ yield;
1287
+ if (!mask[c])
1288
+ continue;
1188
1289
  const x = out[i + c] / 255;
1189
1290
  let y = x;
1190
1291
  if (fn === "polynomial") {
@@ -1214,14 +1315,20 @@ function applyMagickFunction(img, funcRaw, paramsRaw, channels) {
1214
1315
  }
1215
1316
  return { ...img, data: out };
1216
1317
  }
1217
- function applyMagickClut(baseImg, lutImg, channels) {
1318
+ function* applyMagickClutSteps(baseImg, lutImg, channels, signal) {
1319
+ let cooperativeWork = 0;
1218
1320
  const out = new Uint8Array(baseImg.data);
1219
1321
  const horiz = lutImg.width >= lutImg.height;
1220
1322
  const len = Math.max(1, horiz ? lutImg.width : lutImg.height);
1221
1323
  const mask = [channels.r, channels.g, channels.b, channels.a];
1222
1324
  for (let i = 0; i < out.length; i += 4) {
1325
+ if (++cooperativeWork % 65536 === 0)
1326
+ yield;
1223
1327
  for (let c = 0; c < 4; c++) {
1224
- if (!mask[c]) continue;
1328
+ if (++cooperativeWork % 65536 === 0)
1329
+ yield;
1330
+ if (!mask[c])
1331
+ continue;
1225
1332
  const t = out[i + c] / 255;
1226
1333
  const pos = Math.max(0, Math.min(len - 1, Math.round(t * (len - 1))));
1227
1334
  const lx = horiz ? pos : 0;
@@ -1614,17 +1721,25 @@ function compileSingleFxExpr(src) {
1614
1721
  }
1615
1722
  return parseTernary();
1616
1723
  }
1617
- function applyMagickFx(stack, exprStr, channels) {
1724
+ function* applyMagickFxSteps(stack, exprStr, channels, signal) {
1725
+ let cooperativeWork = 0;
1618
1726
  const base = stack[0];
1619
1727
  const out = new Uint8Array(base.data);
1620
1728
  const evalFn = compileFxExpression(exprStr);
1621
1729
  const mask = [channels.r, channels.g, channels.b, channels.a];
1622
1730
  const vars = /* @__PURE__ */ new Map();
1623
1731
  for (let y = 0; y < base.height; y++) {
1732
+ if (++cooperativeWork % 65536 === 0)
1733
+ yield;
1624
1734
  for (let x = 0; x < base.width; x++) {
1735
+ if (++cooperativeWork % 65536 === 0)
1736
+ yield;
1625
1737
  const idx = (y * base.width + x) * 4;
1626
1738
  for (let c = 0; c < 4; c++) {
1627
- if (!mask[c]) continue;
1739
+ if (++cooperativeWork % 65536 === 0)
1740
+ yield;
1741
+ if (!mask[c])
1742
+ continue;
1628
1743
  vars.clear();
1629
1744
  const val = evalFn({
1630
1745
  stack,
@@ -1665,7 +1780,8 @@ function sampleBilinear(img, sx, sy, bg, out, outOff) {
1665
1780
  out[outOff + c] = clampByteVal(v0 * (1 - fy) + v1 * fy);
1666
1781
  }
1667
1782
  }
1668
- function applyMagickShear(img, geomStr, bg) {
1783
+ function* applyMagickShearSteps(img, geomStr, bg, signal) {
1784
+ let cooperativeWork = 0;
1669
1785
  const g = parseMagickGeometry(geomStr);
1670
1786
  const degX = g.width ?? 0;
1671
1787
  const degY = g.height ?? 0;
@@ -1680,7 +1796,11 @@ function applyMagickShear(img, geomStr, bg) {
1680
1796
  const cyDst = (outH - 1) / 2;
1681
1797
  const det = 1 - tanX * tanY || 1;
1682
1798
  for (let y = 0; y < outH; y++) {
1799
+ if (++cooperativeWork % 65536 === 0)
1800
+ yield;
1683
1801
  for (let x = 0; x < outW; x++) {
1802
+ if (++cooperativeWork % 65536 === 0)
1803
+ yield;
1684
1804
  const dx = x - cxDst;
1685
1805
  const dy = y - cyDst;
1686
1806
  const sx = cxSrc + (dx - tanX * dy) / det;
@@ -1714,7 +1834,8 @@ function solveLinearSystem(A, b) {
1714
1834
  }
1715
1835
  return M.map((row) => row[n]);
1716
1836
  }
1717
- function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1837
+ function* applyMagickDistortSteps(img, methodRaw, argsRaw, bg, signal) {
1838
+ let cooperativeWork = 0;
1718
1839
  const method = methodRaw.toLowerCase().replace(/[-_]/g, "");
1719
1840
  const nums = argsRaw.trim().split(/[\s,]+/).filter((s) => s.length > 0).map(Number);
1720
1841
  const w = img.width;
@@ -1768,7 +1889,11 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1768
1889
  const cosA = Math.cos(rad);
1769
1890
  const sinA = Math.sin(rad);
1770
1891
  for (let y = 0; y < h; y++) {
1892
+ if (++cooperativeWork % 65536 === 0)
1893
+ yield;
1771
1894
  for (let x = 0; x < w; x++) {
1895
+ if (++cooperativeWork % 65536 === 0)
1896
+ yield;
1772
1897
  const dx = x - nx;
1773
1898
  const dy = y - ny;
1774
1899
  const sx = cx + (dx * cosA + dy * sinA) / scaleX;
@@ -1786,6 +1911,8 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1786
1911
  const A = [];
1787
1912
  const bVec = [];
1788
1913
  for (let p = 0; p < 4; p++) {
1914
+ if (++cooperativeWork % 65536 === 0)
1915
+ yield;
1789
1916
  const sx = nums[p * 4];
1790
1917
  const sy = nums[p * 4 + 1];
1791
1918
  const dx = nums[p * 4 + 2];
@@ -1802,7 +1929,11 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1802
1929
  }
1803
1930
  const [c0, c1, c2, c3, c4, c5, c6, c7] = hCoeff;
1804
1931
  for (let y = 0; y < h; y++) {
1932
+ if (++cooperativeWork % 65536 === 0)
1933
+ yield;
1805
1934
  for (let x = 0; x < w; x++) {
1935
+ if (++cooperativeWork % 65536 === 0)
1936
+ yield;
1806
1937
  const denom = c6 * x + c7 * y + 1 || 1e-9;
1807
1938
  const sx = (c0 * x + c1 * y + c2) / denom;
1808
1939
  const sy = (c3 * x + c4 * y + c5) / denom;
@@ -1816,6 +1947,8 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1816
1947
  const bx = [];
1817
1948
  const by = [];
1818
1949
  for (let p = 0; p < 3; p++) {
1950
+ if (++cooperativeWork % 65536 === 0)
1951
+ yield;
1819
1952
  const sx = nums[p * 4];
1820
1953
  const sy = nums[p * 4 + 1];
1821
1954
  const dx = nums[p * 4 + 2];
@@ -1827,7 +1960,11 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1827
1960
  const rx = solveLinearSystem(A, bx);
1828
1961
  const ry = solveLinearSystem(A, by);
1829
1962
  for (let y = 0; y < h; y++) {
1963
+ if (++cooperativeWork % 65536 === 0)
1964
+ yield;
1830
1965
  for (let x = 0; x < w; x++) {
1966
+ if (++cooperativeWork % 65536 === 0)
1967
+ yield;
1831
1968
  const sx = rx[0] * x + rx[1] * y + rx[2];
1832
1969
  const sy = ry[0] * x + ry[1] * y + ry[2];
1833
1970
  sampleBilinear(img, sx, sy, bg, out, (y * w + x) * 4);
@@ -1844,7 +1981,11 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1844
1981
  const cy = nums[5] ?? (h - 1) / 2;
1845
1982
  const rNorm = Math.min(w, h) / 2;
1846
1983
  for (let y = 0; y < h; y++) {
1984
+ if (++cooperativeWork % 65536 === 0)
1985
+ yield;
1847
1986
  for (let x = 0; x < w; x++) {
1987
+ if (++cooperativeWork % 65536 === 0)
1988
+ yield;
1848
1989
  const dx = (x - cx) / rNorm;
1849
1990
  const dy = (y - cy) / rNorm;
1850
1991
  const r = Math.hypot(dx, dy);
@@ -1858,7 +1999,8 @@ function applyMagickDistort(img, methodRaw, argsRaw, bg) {
1858
1999
  }
1859
2000
  return img;
1860
2001
  }
1861
- function applyMagickSwirl(img, degrees, bg) {
2002
+ function* applyMagickSwirlSteps(img, degrees, bg, signal) {
2003
+ let cooperativeWork = 0;
1862
2004
  const w = img.width;
1863
2005
  const h = img.height;
1864
2006
  const out = new Uint8Array(w * h * 4);
@@ -1867,7 +2009,11 @@ function applyMagickSwirl(img, degrees, bg) {
1867
2009
  const maxR = Math.max(cx, cy, 1);
1868
2010
  const radTotal = degrees * Math.PI / 180;
1869
2011
  for (let y = 0; y < h; y++) {
2012
+ if (++cooperativeWork % 65536 === 0)
2013
+ yield;
1870
2014
  for (let x = 0; x < w; x++) {
2015
+ if (++cooperativeWork % 65536 === 0)
2016
+ yield;
1871
2017
  const dx = x - cx;
1872
2018
  const dy = y - cy;
1873
2019
  const r = Math.hypot(dx, dy);
@@ -1886,7 +2032,8 @@ function applyMagickSwirl(img, degrees, bg) {
1886
2032
  }
1887
2033
  return { ...img, data: out };
1888
2034
  }
1889
- function applyMagickImplode(img, amount, bg) {
2035
+ function* applyMagickImplodeSteps(img, amount, bg, signal) {
2036
+ let cooperativeWork = 0;
1890
2037
  const w = img.width;
1891
2038
  const h = img.height;
1892
2039
  const out = new Uint8Array(w * h * 4);
@@ -1896,7 +2043,11 @@ function applyMagickImplode(img, amount, bg) {
1896
2043
  const clamped = Math.max(-0.95, Math.min(0.95, amount));
1897
2044
  const exp = 1 / (1 - clamped);
1898
2045
  for (let y = 0; y < h; y++) {
2046
+ if (++cooperativeWork % 65536 === 0)
2047
+ yield;
1899
2048
  for (let x = 0; x < w; x++) {
2049
+ if (++cooperativeWork % 65536 === 0)
2050
+ yield;
1900
2051
  const dx = x - cx;
1901
2052
  const dy = y - cy;
1902
2053
  const r = Math.hypot(dx, dy);
@@ -1911,7 +2062,8 @@ function applyMagickImplode(img, amount, bg) {
1911
2062
  }
1912
2063
  return { ...img, data: out };
1913
2064
  }
1914
- function applyMagickWave(img, geomStr, bg) {
2065
+ function* applyMagickWaveSteps(img, geomStr, bg, signal) {
2066
+ let cooperativeWork = 0;
1915
2067
  const g = parseMagickGeometry(geomStr);
1916
2068
  const amp = g.width ?? 5;
1917
2069
  const waveLen = Math.max(1, g.height ?? 50);
@@ -1921,14 +2073,19 @@ function applyMagickWave(img, geomStr, bg) {
1921
2073
  const out = new Uint8Array(outW * outH * 4);
1922
2074
  const yPad = Math.abs(amp);
1923
2075
  for (let y = 0; y < outH; y++) {
2076
+ if (++cooperativeWork % 65536 === 0)
2077
+ yield;
1924
2078
  for (let x = 0; x < outW; x++) {
2079
+ if (++cooperativeWork % 65536 === 0)
2080
+ yield;
1925
2081
  const sy = y - yPad - amp * Math.sin(2 * Math.PI * x / waveLen);
1926
2082
  sampleBilinear(img, x, sy, bg, out, (y * outW + x) * 4);
1927
2083
  }
1928
2084
  }
1929
2085
  return { ...img, width: outW, height: outH, data: out, hasAlpha: true };
1930
2086
  }
1931
- function applyMagickShadow(img, geomStr, shadowColor) {
2087
+ function* applyMagickShadowSteps(img, geomStr, shadowColor, signal) {
2088
+ let cooperativeWork = 0;
1932
2089
  const g = parseMagickGeometry(geomStr);
1933
2090
  const opacity = Math.max(0, Math.min(100, g.width ?? 80)) / 100;
1934
2091
  const sigma = Math.max(0.5, g.height ?? 3);
@@ -1939,10 +2096,15 @@ function applyMagickShadow(img, geomStr, shadowColor) {
1939
2096
  const offX = pad + Math.round(g.x);
1940
2097
  const offY = pad + Math.round(g.y);
1941
2098
  for (let y = 0; y < img.height; y++) {
2099
+ if (++cooperativeWork % 65536 === 0)
2100
+ yield;
1942
2101
  for (let x = 0; x < img.width; x++) {
2102
+ if (++cooperativeWork % 65536 === 0)
2103
+ yield;
1943
2104
  const dx = x + offX;
1944
2105
  const dy = y + offY;
1945
- if (dx < 0 || dy < 0 || dx >= outW || dy >= outH) continue;
2106
+ if (dx < 0 || dy < 0 || dx >= outW || dy >= outH)
2107
+ continue;
1946
2108
  const srcA = img.data[(y * img.width + x) * 4 + 3];
1947
2109
  const dstIdx = (dy * outW + dx) * 4;
1948
2110
  data[dstIdx] = shadowColor.r;
@@ -1960,14 +2122,19 @@ function applyMagickShadow(img, geomStr, shadowColor) {
1960
2122
  };
1961
2123
  return blurImage(shadowBase, sigma);
1962
2124
  }
1963
- function applyMagickVignette(img, _geomStr, bg) {
2125
+ function* applyMagickVignetteSteps(img, _geomStr, bg, signal) {
2126
+ let cooperativeWork = 0;
1964
2127
  const w = img.width;
1965
2128
  const h = img.height;
1966
2129
  const out = new Uint8Array(img.data);
1967
2130
  const cx = (w - 1) / 2;
1968
2131
  const cy = (h - 1) / 2;
1969
2132
  for (let y = 0; y < h; y++) {
2133
+ if (++cooperativeWork % 65536 === 0)
2134
+ yield;
1970
2135
  for (let x = 0; x < w; x++) {
2136
+ if (++cooperativeWork % 65536 === 0)
2137
+ yield;
1971
2138
  const nx = (x - cx) / Math.max(1, cx);
1972
2139
  const ny = (y - cy) / Math.max(1, cy);
1973
2140
  const d = Math.hypot(nx, ny);
@@ -1980,11 +2147,14 @@ function applyMagickVignette(img, _geomStr, bg) {
1980
2147
  }
1981
2148
  return { ...img, data: out };
1982
2149
  }
1983
- function applyMagickSepiaTone(img, threshStr) {
2150
+ function* applyMagickSepiaToneSteps(img, threshStr, signal) {
2151
+ let cooperativeWork = 0;
1984
2152
  const raw = parseFloat(threshStr);
1985
2153
  const strength = Math.max(0, Math.min(1, (threshStr.endsWith("%") ? raw : raw / 255) / 100 || 0.8));
1986
2154
  const out = new Uint8Array(img.data);
1987
2155
  for (let i = 0; i < out.length; i += 4) {
2156
+ if (++cooperativeWork % 65536 === 0)
2157
+ yield;
1988
2158
  const r = out[i];
1989
2159
  const g = out[i + 1];
1990
2160
  const b = out[i + 2];
@@ -1997,40 +2167,60 @@ function applyMagickSepiaTone(img, threshStr) {
1997
2167
  }
1998
2168
  return { ...img, data: out };
1999
2169
  }
2000
- function applyMagickSolarize(img, threshStr) {
2170
+ function* applyMagickSolarizeSteps(img, threshStr, signal) {
2171
+ let cooperativeWork = 0;
2001
2172
  const raw = parseFloat(threshStr);
2002
2173
  const thresh = threshStr.endsWith("%") ? raw / 100 * 255 : raw;
2003
2174
  const out = new Uint8Array(img.data);
2004
2175
  for (let i = 0; i < out.length; i += 4) {
2005
- if (out[i] > thresh) out[i] = 255 - out[i];
2006
- if (out[i + 1] > thresh) out[i + 1] = 255 - out[i + 1];
2007
- if (out[i + 2] > thresh) out[i + 2] = 255 - out[i + 2];
2176
+ if (++cooperativeWork % 65536 === 0)
2177
+ yield;
2178
+ if (out[i] > thresh)
2179
+ out[i] = 255 - out[i];
2180
+ if (out[i + 1] > thresh)
2181
+ out[i + 1] = 255 - out[i + 1];
2182
+ if (out[i + 2] > thresh)
2183
+ out[i + 2] = 255 - out[i + 2];
2008
2184
  }
2009
2185
  return { ...img, data: out };
2010
2186
  }
2011
- function applyMagickPosterize(img, levelsRaw) {
2187
+ function* applyMagickPosterizeSteps(img, levelsRaw, signal) {
2188
+ let cooperativeWork = 0;
2012
2189
  const levels = Math.max(2, Math.min(256, Math.round(levelsRaw)));
2013
2190
  const step = 255 / (levels - 1);
2014
2191
  const out = new Uint8Array(img.data);
2015
2192
  for (let i = 0; i < out.length; i += 4) {
2193
+ if (++cooperativeWork % 65536 === 0)
2194
+ yield;
2016
2195
  out[i] = clampByteVal(Math.round(out[i] / 255 * (levels - 1)) * step);
2017
2196
  out[i + 1] = clampByteVal(Math.round(out[i + 1] / 255 * (levels - 1)) * step);
2018
2197
  out[i + 2] = clampByteVal(Math.round(out[i + 2] / 255 * (levels - 1)) * step);
2019
2198
  }
2020
2199
  return { ...img, data: out };
2021
2200
  }
2022
- function applyMagickConvolve3x3(img, kernel, bias = 0) {
2201
+ function* applyMagickConvolve3x3Steps(img, kernel, bias = 0, signal) {
2202
+ let cooperativeWork = 0;
2023
2203
  const w = img.width;
2024
2204
  const h = img.height;
2025
2205
  const out = new Uint8Array(img.data);
2026
2206
  for (let y = 0; y < h; y++) {
2207
+ if (++cooperativeWork % 65536 === 0)
2208
+ yield;
2027
2209
  for (let x = 0; x < w; x++) {
2210
+ if (++cooperativeWork % 65536 === 0)
2211
+ yield;
2028
2212
  for (let c = 0; c < 3; c++) {
2213
+ if (++cooperativeWork % 65536 === 0)
2214
+ yield;
2029
2215
  let sum = bias;
2030
2216
  let kIdx = 0;
2031
2217
  for (let ky = -1; ky <= 1; ky++) {
2218
+ if (++cooperativeWork % 65536 === 0)
2219
+ yield;
2032
2220
  const sy = Math.max(0, Math.min(h - 1, y + ky));
2033
2221
  for (let kx = -1; kx <= 1; kx++) {
2222
+ if (++cooperativeWork % 65536 === 0)
2223
+ yield;
2034
2224
  const sx = Math.max(0, Math.min(w - 1, x + kx));
2035
2225
  sum += img.data[(sy * w + sx) * 4 + c] * kernel[kIdx++];
2036
2226
  }
@@ -2175,7 +2365,8 @@ function parseCompose(raw) {
2175
2365
  return "over";
2176
2366
  }
2177
2367
  }
2178
- function applyMagickCompositeLayer(dst, src, modeRaw, left, top, composeArgs) {
2368
+ function* applyMagickCompositeLayerSteps(dst, src, modeRaw, left, top, composeArgs, signal) {
2369
+ let cooperativeWork = 0;
2179
2370
  const norm = modeRaw.toLowerCase().replace(/[-_\s]/g, "");
2180
2371
  const out = new Uint8Array(dst.data);
2181
2372
  const dw = dst.width;
@@ -2183,11 +2374,17 @@ function applyMagickCompositeLayer(dst, src, modeRaw, left, top, composeArgs) {
2183
2374
  const sw = src.width;
2184
2375
  const sh = src.height;
2185
2376
  for (let sy = 0; sy < sh; sy++) {
2377
+ if (++cooperativeWork % 65536 === 0)
2378
+ yield;
2186
2379
  const dy = top + sy;
2187
- if (dy < 0 || dy >= dh) continue;
2380
+ if (dy < 0 || dy >= dh)
2381
+ continue;
2188
2382
  for (let sx = 0; sx < sw; sx++) {
2383
+ if (++cooperativeWork % 65536 === 0)
2384
+ yield;
2189
2385
  const dx = left + sx;
2190
- if (dx < 0 || dx >= dw) continue;
2386
+ if (dx < 0 || dx >= dw)
2387
+ continue;
2191
2388
  const sIdx = (sy * sw + sx) * 4;
2192
2389
  const dIdx = (dy * dw + dx) * 4;
2193
2390
  const sr = src.data[sIdx];
@@ -2329,6 +2526,8 @@ function applyMagickCompositeLayer(dst, src, modeRaw, left, top, composeArgs) {
2329
2526
  const sChan = [sr / 255, sg / 255, sb / 255];
2330
2527
  const dChan = [dr / 255, dg / 255, db / 255];
2331
2528
  for (let c = 0; c < 3; c++) {
2529
+ if (++cooperativeWork % 65536 === 0)
2530
+ yield;
2332
2531
  const sc = sChan[c];
2333
2532
  const dc = dChan[c];
2334
2533
  if (norm === "darken") {
@@ -2342,9 +2541,12 @@ function applyMagickCompositeLayer(dst, src, modeRaw, left, top, composeArgs) {
2342
2541
  out[dIdx + c] = clampByteVal(comp * 255);
2343
2542
  } else {
2344
2543
  let f = 0;
2345
- if (norm === "multiply") f = sc * dc;
2346
- else if (norm === "screen") f = sc + dc - sc * dc;
2347
- else f = dc <= 0.5 ? 2 * sc * dc : 1 - 2 * (1 - sc) * (1 - dc);
2544
+ if (norm === "multiply")
2545
+ f = sc * dc;
2546
+ else if (norm === "screen")
2547
+ f = sc + dc - sc * dc;
2548
+ else
2549
+ f = dc <= 0.5 ? 2 * sc * dc : 1 - 2 * (1 - sc) * (1 - dc);
2348
2550
  const comp = f * sa * da + sc * sa * (1 - da) + dc * da * (1 - sa);
2349
2551
  const unpremul = gamma > 1e-6 && norm === "overlay" ? comp / gamma : comp;
2350
2552
  out[dIdx + c] = clampByteVal(unpremul * 255);
@@ -2365,7 +2567,8 @@ function applyMagickCompositeLayer(dst, src, modeRaw, left, top, composeArgs) {
2365
2567
  const sy0 = Math.max(0, -oy);
2366
2568
  const sx1 = Math.min(src.width, dst.width - ox);
2367
2569
  const sy1 = Math.min(src.height, dst.height - oy);
2368
- if (sx1 <= sx0 || sy1 <= sy0) return dst;
2570
+ if (sx1 <= sx0 || sy1 <= sy0)
2571
+ return dst;
2369
2572
  const clipped = extractImage(src, { left: sx0, top: sy0, width: sx1 - sx0, height: sy1 - sy0 });
2370
2573
  return compositeImage(dst, [rgbaToCompositeLayer(clipped, Math.max(0, ox), Math.max(0, oy), parseCompose(modeRaw))]);
2371
2574
  }
@@ -2537,7 +2740,8 @@ function applyMagickCropToStack(img, geomStr, gravity) {
2537
2740
  })
2538
2741
  ];
2539
2742
  }
2540
- function applyMagickExtent(img, geomStr, state) {
2743
+ function* applyMagickExtentSteps(img, geomStr, state, signal) {
2744
+ yield;
2541
2745
  const g = parseMagickGeometry(geomStr);
2542
2746
  const targetW = Math.max(1, Math.round(g.width ?? img.width));
2543
2747
  const targetH = Math.max(1, Math.round(g.height ?? img.height));
@@ -2562,7 +2766,9 @@ function applyMagickExtent(img, geomStr, state) {
2562
2766
  });
2563
2767
  return compositeImage(canvas, [rgbaToCompositeLayer(subImg, dstX0, dstY0, "over")]);
2564
2768
  }
2565
- function applyMagickDraw(img, drawCmd, state) {
2769
+ function* applyMagickDrawSteps(img, drawCmd, state, signal) {
2770
+ yield;
2771
+ let cooperativeWork = 0;
2566
2772
  const svgElements = [];
2567
2773
  let fill = rgbaToCss(state.fill);
2568
2774
  let stroke = rgbaToCss(state.stroke);
@@ -2571,12 +2777,17 @@ function applyMagickDraw(img, drawCmd, state) {
2571
2777
  const tokens = [];
2572
2778
  let m;
2573
2779
  while ((m = tokenRe.exec(drawCmd)) !== null) {
2574
- if (m[0] === ",") continue;
2780
+ if (++cooperativeWork % 65536 === 0)
2781
+ yield;
2782
+ if (m[0] === ",")
2783
+ continue;
2575
2784
  tokens.push(m[1] ?? m[2] ?? m[3] ?? "");
2576
2785
  }
2577
2786
  let i = 0;
2578
2787
  const num = () => Number(tokens[i++] ?? 0);
2579
2788
  while (i < tokens.length) {
2789
+ if (++cooperativeWork % 65536 === 0)
2790
+ yield;
2580
2791
  const cmd = tokens[i++].toLowerCase();
2581
2792
  if (cmd === "fill") {
2582
2793
  fill = rgbaToCss(parseColor2(tokens[i++] ?? "#000000"));
@@ -2594,14 +2805,10 @@ function applyMagickDraw(img, drawCmd, state) {
2594
2805
  const rw = Math.max(1, Math.abs(x1 - x0) + 1);
2595
2806
  const rh = Math.max(1, Math.abs(y1 - y0) + 1);
2596
2807
  if (fill !== "none") {
2597
- svgElements.push(
2598
- `<rect x="${rx}" y="${ry}" width="${rw}" height="${rh}" fill="${fill}"/>`
2599
- );
2808
+ svgElements.push(`<rect x="${rx}" y="${ry}" width="${rw}" height="${rh}" fill="${fill}"/>`);
2600
2809
  }
2601
2810
  if (stroke !== "none" && strokeWidth > 0) {
2602
- svgElements.push(
2603
- `<polygon points="${rx},${ry} ${rx + rw - 1},${ry} ${rx + rw - 1},${ry + rh - 1} ${rx},${ry + rh - 1}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2604
- );
2811
+ svgElements.push(`<polygon points="${rx},${ry} ${rx + rw - 1},${ry} ${rx + rw - 1},${ry + rh - 1} ${rx},${ry + rh - 1}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2605
2812
  }
2606
2813
  } else if (cmd === "roundrectangle") {
2607
2814
  const x0 = num();
@@ -2615,14 +2822,10 @@ function applyMagickDraw(img, drawCmd, state) {
2615
2822
  const rw = Math.max(1, Math.abs(x1 - x0) + 1);
2616
2823
  const rh = Math.max(1, Math.abs(y1 - y0) + 1);
2617
2824
  if (fill !== "none") {
2618
- svgElements.push(
2619
- `<rect x="${rx}" y="${ry}" width="${rw}" height="${rh}" rx="${wc}" ry="${hc}" fill="${fill}"/>`
2620
- );
2825
+ svgElements.push(`<rect x="${rx}" y="${ry}" width="${rw}" height="${rh}" rx="${wc}" ry="${hc}" fill="${fill}"/>`);
2621
2826
  }
2622
2827
  if (stroke !== "none" && strokeWidth > 0) {
2623
- svgElements.push(
2624
- `<polygon points="${rx},${ry} ${rx + rw - 1},${ry} ${rx + rw - 1},${ry + rh - 1} ${rx},${ry + rh - 1}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2625
- );
2828
+ svgElements.push(`<polygon points="${rx},${ry} ${rx + rw - 1},${ry} ${rx + rw - 1},${ry + rh - 1} ${rx},${ry + rh - 1}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2626
2829
  }
2627
2830
  } else if (cmd === "circle") {
2628
2831
  const cx = num();
@@ -2630,9 +2833,7 @@ function applyMagickDraw(img, drawCmd, state) {
2630
2833
  const px = num();
2631
2834
  const py = num();
2632
2835
  const r = Math.max(1, Math.hypot(px - cx, py - cy));
2633
- svgElements.push(
2634
- `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2635
- );
2836
+ svgElements.push(`<circle cx="${cx}" cy="${cy}" r="${r}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2636
2837
  } else if (cmd === "ellipse") {
2637
2838
  const cx = num();
2638
2839
  const cy = num();
@@ -2640,18 +2841,14 @@ function applyMagickDraw(img, drawCmd, state) {
2640
2841
  const ry = num();
2641
2842
  num();
2642
2843
  num();
2643
- svgElements.push(
2644
- `<ellipse cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2645
- );
2844
+ svgElements.push(`<ellipse cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2646
2845
  } else if (cmd === "line") {
2647
2846
  const x0 = num();
2648
2847
  const y0 = num();
2649
2848
  const x1 = num();
2650
2849
  const y1 = num();
2651
2850
  const lineStroke = stroke === "none" ? fill : stroke;
2652
- svgElements.push(
2653
- `<line x1="${x0}" y1="${y0}" x2="${x1}" y2="${y1}" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`
2654
- );
2851
+ svgElements.push(`<line x1="${x0}" y1="${y0}" x2="${x1}" y2="${y1}" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`);
2655
2852
  } else if (cmd === "point") {
2656
2853
  const x = num();
2657
2854
  const y = num();
@@ -2660,58 +2857,52 @@ function applyMagickDraw(img, drawCmd, state) {
2660
2857
  const x = num();
2661
2858
  const y = num();
2662
2859
  const txt = tokens[i++] ?? "";
2663
- svgElements.push(
2664
- `<text x="${x}" y="${y}" font-size="${state.pointsize}" fill="${fill}">${escapeXml(txt)}</text>`
2665
- );
2860
+ svgElements.push(`<text x="${x}" y="${y}" font-size="${state.pointsize}" fill="${fill}">${escapeXml(txt)}</text>`);
2666
2861
  } else if (cmd === "polygon" || cmd === "polyline") {
2667
2862
  const pts = [];
2668
2863
  while (i < tokens.length && !Number.isNaN(Number(tokens[i]))) {
2864
+ if (++cooperativeWork % 65536 === 0)
2865
+ yield;
2669
2866
  const px = num();
2670
2867
  const py = num();
2671
2868
  pts.push(`${px},${py}`);
2672
2869
  }
2673
2870
  if (pts.length >= 2) {
2674
2871
  if (cmd === "polygon") {
2675
- svgElements.push(
2676
- `<polygon points="${pts.join(" ")}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2677
- );
2872
+ svgElements.push(`<polygon points="${pts.join(" ")}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2678
2873
  } else {
2679
2874
  const lineStroke = stroke === "none" ? fill : stroke;
2680
- svgElements.push(
2681
- `<polyline points="${pts.join(" ")}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`
2682
- );
2875
+ svgElements.push(`<polyline points="${pts.join(" ")}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`);
2683
2876
  }
2684
2877
  }
2685
2878
  } else if (cmd === "bezier") {
2686
2879
  const pts = [];
2687
2880
  while (i < tokens.length && !Number.isNaN(Number(tokens[i]))) {
2881
+ if (++cooperativeWork % 65536 === 0)
2882
+ yield;
2688
2883
  pts.push({ x: num(), y: num() });
2689
2884
  }
2690
2885
  if (pts.length === 3) {
2691
2886
  const lineStroke = stroke === "none" ? fill : stroke;
2692
- svgElements.push(
2693
- `<path d="M ${pts[0].x} ${pts[0].y} Q ${pts[1].x} ${pts[1].y} ${pts[2].x} ${pts[2].y}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`
2694
- );
2887
+ svgElements.push(`<path d="M ${pts[0].x} ${pts[0].y} Q ${pts[1].x} ${pts[1].y} ${pts[2].x} ${pts[2].y}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`);
2695
2888
  } else if (pts.length >= 4) {
2696
2889
  const lineStroke = stroke === "none" ? fill : stroke;
2697
2890
  const rest = pts.slice(1).map((p) => `${p.x} ${p.y}`).join(" ");
2698
- svgElements.push(
2699
- `<path d="M ${pts[0].x} ${pts[0].y} C ${rest}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`
2700
- );
2891
+ svgElements.push(`<path d="M ${pts[0].x} ${pts[0].y} C ${rest}" fill="none" stroke="${lineStroke}" stroke-width="${Math.max(1, strokeWidth)}"/>`);
2701
2892
  }
2702
2893
  } else if (cmd === "path") {
2703
2894
  const d = tokens[i++] ?? "";
2704
- svgElements.push(
2705
- `<path d="${escapeXml(d)}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
2706
- );
2895
+ svgElements.push(`<path d="${escapeXml(d)}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`);
2707
2896
  }
2708
2897
  }
2709
- if (svgElements.length === 0) return img;
2898
+ if (svgElements.length === 0)
2899
+ return img;
2710
2900
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${img.width}" height="${img.height}">${svgElements.join("")}</svg>`;
2711
2901
  const overlay = decodeImage(new TextEncoder().encode(svg), { density: state.density });
2712
2902
  return compositeImage(img, [rgbaToCompositeLayer(overlay, 0, 0, "over")]);
2713
2903
  }
2714
- function applyMagickAnnotate(img, offsetStr, text, state) {
2904
+ function* applyMagickAnnotateSteps(img, offsetStr, text, state, signal) {
2905
+ yield;
2715
2906
  const g = parseMagickGeometry(offsetStr);
2716
2907
  const fontSize = Math.max(8, state.pointsize);
2717
2908
  const estW = Math.max(8, Math.ceil(text.length * fontSize * 0.6));
@@ -2929,14 +3120,14 @@ function formatIdentifyCustom(fmt, filePath, meta, byteLen, rawBytes) {
2929
3120
  }
2930
3121
  return out;
2931
3122
  }
2932
- async function runIdentifyCli(argv, files, stdinBytes) {
2933
- return runIdentifyCliSync(argv, files, stdinBytes);
2934
- }
2935
- function runIdentifyCliSync(argv, files, stdinBytes) {
3123
+ function* runIdentifyCliSteps(argv, files, stdinBytes, signal) {
3124
+ let cooperativeWork = 63;
2936
3125
  let verbose = false;
2937
3126
  let customFormat;
2938
3127
  const targets = [];
2939
3128
  for (let i = 0; i < argv.length; i++) {
3129
+ if (++cooperativeWork % 64 === 0)
3130
+ yield;
2940
3131
  const a = argv[i];
2941
3132
  if (a === "--help" || a === "-help" || a === "-h") {
2942
3133
  return {
@@ -2972,6 +3163,7 @@ function runIdentifyCliSync(argv, files, stdinBytes) {
2972
3163
  const errParts = [];
2973
3164
  let exitCode = 0;
2974
3165
  for (const inPath of targets) {
3166
+ yield;
2975
3167
  const bracketMatch = /^(.*)\[(\d+)\]$/.exec(inPath);
2976
3168
  let baseInPath = bracketMatch ? bracketMatch[1] : inPath;
2977
3169
  const colon = baseInPath.indexOf(":");
@@ -2995,8 +3187,7 @@ function runIdentifyCliSync(argv, files, stdinBytes) {
2995
3187
  outParts.push(formatIdentifyCustom(customFormat, baseInPath, meta, bytes.byteLength, bytes));
2996
3188
  } else if (verbose) {
2997
3189
  const stats = computeImageStats(decodeImage(bytes, inputOptions));
2998
- outParts.push(
2999
- `Image: ${inPath}
3190
+ outParts.push(`Image: ${inPath}
3000
3191
  Format: ${meta.format.toUpperCase()}
3001
3192
  Geometry: ${meta.width}x${meta.height}+0+0
3002
3193
  Resolution: ${meta.density}x${meta.density}
@@ -3006,13 +3197,10 @@ function runIdentifyCliSync(argv, files, stdinBytes) {
3006
3197
  Alpha: ${meta.hasAlpha ? "True" : "False"}
3007
3198
  Filesize: ${bytes.byteLength}B
3008
3199
  Entropy: ${stats.entropy.toFixed(4)}
3009
- `
3010
- );
3200
+ `);
3011
3201
  } else {
3012
- outParts.push(
3013
- `${inPath} ${meta.format.toUpperCase()} ${meta.width}x${meta.height} ${meta.width}x${meta.height}+0+0 ${bitDepth}-bit ${spaceLabel} ${bytes.byteLength}B 0.000u 0:00.000
3014
- `
3015
- );
3202
+ outParts.push(`${inPath} ${meta.format.toUpperCase()} ${meta.width}x${meta.height} ${meta.width}x${meta.height}+0+0 ${bitDepth}-bit ${spaceLabel} ${bytes.byteLength}B 0.000u 0:00.000
3203
+ `);
3016
3204
  }
3017
3205
  } catch (err) {
3018
3206
  errParts.push(`identify: improper image header '${inPath}': ${err.message}
@@ -3026,6 +3214,17 @@ function runIdentifyCliSync(argv, files, stdinBytes) {
3026
3214
  stderr: errParts.join("")
3027
3215
  };
3028
3216
  }
3217
+ async function runIdentifyCli(argv, files, stdinBytes, signal) {
3218
+ return drainSteps(runIdentifyCliSteps(argv, files, stdinBytes, signal), signal);
3219
+ }
3220
+ function runIdentifyCliSync(argv, files, stdinBytes, signal) {
3221
+ const steps = runIdentifyCliSteps(argv, files, stdinBytes, signal);
3222
+ let next = steps.next();
3223
+ while (!next.done) {
3224
+ next = steps.next();
3225
+ }
3226
+ return next.value;
3227
+ }
3029
3228
  function parseMagickIndexSpec(spec, length) {
3030
3229
  if (length <= 0) return [];
3031
3230
  const resolve = (n) => n < 0 ? Math.max(0, length + n) : Math.min(Math.max(0, n), length - 1);
@@ -3052,23 +3251,29 @@ function parseMagickIndexSpec(spec, length) {
3052
3251
  }
3053
3252
  return out;
3054
3253
  }
3055
- function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinBytes) {
3254
+ function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], stdinBytes, signal) {
3255
+ let cooperativeWork = 63;
3056
3256
  let stack = [];
3057
3257
  let i = 0;
3058
3258
  while (i < tokens.length) {
3259
+ yield;
3059
3260
  const t = tokens[i];
3060
3261
  if (t === "(") {
3061
3262
  let depth = 1;
3062
3263
  let j = i + 1;
3063
3264
  while (j < tokens.length && depth > 0) {
3064
- if (tokens[j] === "(") depth++;
3065
- else if (tokens[j] === ")") depth--;
3265
+ if (++cooperativeWork % 65536 === 0)
3266
+ yield;
3267
+ if (tokens[j] === "(")
3268
+ depth++;
3269
+ else if (tokens[j] === ")")
3270
+ depth--;
3066
3271
  j++;
3067
3272
  }
3068
3273
  const endIdx = depth === 0 ? j - 1 : j;
3069
3274
  const subTokens = tokens.slice(i + 1, endIdx);
3070
3275
  const subState = { ...state };
3071
- const subResult = evaluatePipelineTokens(subTokens, files, subState, stack, stdinBytes);
3276
+ const subResult = yield* evaluatePipelineTokensSteps(subTokens, files, subState, stack, stdinBytes, signal);
3072
3277
  stack.push(...subResult);
3073
3278
  i = j;
3074
3279
  continue;
@@ -3113,11 +3318,13 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3113
3318
  } else if (t === "-define") {
3114
3319
  const defStr = tokens[++i] ?? "";
3115
3320
  const m = /^compose:args=(.*)$/i.exec(defStr);
3116
- if (m) state.composeArgs = m[1];
3321
+ if (m)
3322
+ state.composeArgs = m[1];
3117
3323
  } else if (t === "-set") {
3118
3324
  const k = (tokens[++i] ?? "").toLowerCase();
3119
3325
  const v = tokens[++i] ?? "";
3120
- if (k === "option:compose:args") state.composeArgs = v;
3326
+ if (k === "option:compose:args")
3327
+ state.composeArgs = v;
3121
3328
  } else if (t === "-write" || t === "+write") {
3122
3329
  const writePath = tokens[++i] ?? "";
3123
3330
  if (stack.length > 0 && writePath && writePath.toLowerCase() !== "null:") {
@@ -3125,6 +3332,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3125
3332
  const { format, path } = inferOutputFormat(writePath, top.format);
3126
3333
  if (stack.length > 1 && (/%0?\d*d/.test(path) || !state.adjoin)) {
3127
3334
  for (let idx = 0; idx < stack.length; idx++) {
3335
+ if (++cooperativeWork % 65536 === 0)
3336
+ yield;
3128
3337
  const framePath = formatSceneOutputPath(path, idx);
3129
3338
  const { data: frameBytes } = encodeImage(stack[idx], { format, quality: state.quality });
3130
3339
  files.set(framePath, frameBytes);
@@ -3151,16 +3360,22 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3151
3360
  } else if (t === "-coalesce" || t === "-deconstruct") {
3152
3361
  } else if (t === "-splice") {
3153
3362
  const geom = tokens[++i] ?? "0x0";
3154
- stack = stack.map((im) => applyMagickSplice(im, geom, state.background, state.gravity));
3363
+ stack = yield* mapSteps(stack, function* (im) {
3364
+ return yield* applyMagickSpliceSteps(im, geom, state.background, state.gravity, signal);
3365
+ });
3155
3366
  } else if (t === "-chop") {
3156
3367
  const geom = tokens[++i] ?? "0x0";
3157
- stack = stack.map((im) => applyMagickChop(im, geom, state.gravity));
3368
+ stack = yield* mapSteps(stack, function* (im) {
3369
+ return yield* applyMagickChopSteps(im, geom, state.gravity, signal);
3370
+ });
3158
3371
  } else if (t === "-roll") {
3159
3372
  const geom = tokens[++i] ?? "+0+0";
3160
- stack = stack.map((im) => applyMagickRoll(im, geom));
3373
+ stack = yield* mapSteps(stack, function* (im) {
3374
+ return yield* applyMagickRollSteps(im, geom, signal);
3375
+ });
3161
3376
  } else if (t === "-morph") {
3162
3377
  const count = Number(tokens[++i] ?? 1);
3163
- stack = applyMagickMorph(stack, count);
3378
+ stack = yield* applyMagickMorphSteps(stack, count, signal);
3164
3379
  } else if (t === "-floodfill") {
3165
3380
  const geom = tokens[++i] ?? "+0+0";
3166
3381
  const nextTok = tokens[i + 1];
@@ -3172,25 +3387,35 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3172
3387
  } catch {
3173
3388
  }
3174
3389
  }
3175
- stack = stack.map((im) => applyMagickFloodfill(im, geom, targetColor, state.fill, state.fuzz));
3390
+ stack = yield* mapSteps(stack, function* (im) {
3391
+ return yield* applyMagickFloodfillSteps(im, geom, targetColor, state.fill, state.fuzz, signal);
3392
+ });
3176
3393
  } else if (t === "-evaluate-sequence") {
3177
3394
  const op = tokens[++i] ?? "Mean";
3178
3395
  if (stack.length > 0) {
3179
- stack = [applyMagickEvaluateSequence(stack, op)];
3396
+ stack = [yield* applyMagickEvaluateSequenceSteps(stack, op, signal)];
3180
3397
  }
3181
3398
  } else if (t === "-convolve") {
3182
3399
  const kSpec = tokens[++i] ?? "1";
3183
- stack = stack.map((im) => applyMagickCustomConvolve(im, kSpec));
3400
+ stack = yield* mapSteps(stack, function* (im) {
3401
+ return yield* applyMagickCustomConvolveSteps(im, kSpec, signal);
3402
+ });
3184
3403
  } else if (t === "-color-matrix" || t === "-recolor") {
3185
3404
  const mSpec = tokens[++i] ?? "1,0,0 0,1,0 0,0,1";
3186
- stack = stack.map((im) => applyMagickColorMatrix(im, mSpec));
3405
+ stack = yield* mapSteps(stack, function* (im) {
3406
+ return yield* applyMagickColorMatrixSteps(im, mSpec, signal);
3407
+ });
3187
3408
  } else if (t === "-equalize") {
3188
- stack = stack.map((im) => applyMagickEqualize(im));
3409
+ stack = yield* mapSteps(stack, function* (im) {
3410
+ return yield* applyMagickEqualizeSteps(im, signal);
3411
+ });
3189
3412
  } else if (t === "-remap") {
3190
3413
  const palSpec = tokens[++i] ?? "";
3191
3414
  const palImg = parseInputOperand(palSpec, files, state, stdinBytes);
3192
3415
  if (palImg) {
3193
- stack = stack.map((im) => applyMagickRemap(im, palImg, state.dither));
3416
+ stack = yield* mapSteps(stack, function* (im) {
3417
+ return yield* applyMagickRemapSteps(im, palImg, state.dither, signal);
3418
+ });
3194
3419
  }
3195
3420
  } else if (t === "-channel") {
3196
3421
  state.channels = parseChannelMask(tokens[++i] ?? "rgb");
@@ -3201,61 +3426,91 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3201
3426
  } else if (t === "-opaque" || t === "+opaque") {
3202
3427
  const targetColor = parseColor2(tokens[++i] ?? "#000000");
3203
3428
  const invert = t === "+opaque";
3204
- stack = stack.map((im) => applyMagickOpaque(im, targetColor, state.fill, state.fuzz, invert));
3429
+ stack = yield* mapSteps(stack, function* (im) {
3430
+ return yield* applyMagickOpaqueSteps(im, targetColor, state.fill, state.fuzz, invert, signal);
3431
+ });
3205
3432
  } else if (t === "-transparent" || t === "+transparent") {
3206
3433
  const targetColor = parseColor2(tokens[++i] ?? "#ffffff");
3207
3434
  const invert = t === "+transparent";
3208
- stack = stack.map((im) => applyMagickTransparent(im, targetColor, state.fuzz, invert));
3435
+ stack = yield* mapSteps(stack, function* (im) {
3436
+ return yield* applyMagickTransparentSteps(im, targetColor, state.fuzz, invert, signal);
3437
+ });
3209
3438
  } else if (t === "-evaluate") {
3210
3439
  const op = tokens[++i] ?? "Add";
3211
3440
  const val = tokens[++i] ?? "0";
3212
- stack = stack.map((im) => applyMagickEvaluate(im, op, val, state.channels));
3441
+ stack = yield* mapSteps(stack, function* (im) {
3442
+ return yield* applyMagickEvaluateSteps(im, op, val, state.channels, signal);
3443
+ });
3213
3444
  } else if (t === "-function") {
3214
3445
  const fn = tokens[++i] ?? "Polynomial";
3215
3446
  const params = tokens[++i] ?? "1,0";
3216
- stack = stack.map((im) => applyMagickFunction(im, fn, params, state.channels));
3447
+ stack = yield* mapSteps(stack, function* (im) {
3448
+ return yield* applyMagickFunctionSteps(im, fn, params, state.channels, signal);
3449
+ });
3217
3450
  } else if (t === "-clut" || t === "-hald-clut") {
3218
3451
  if (stack.length >= 2) {
3219
3452
  const lut = stack[stack.length - 1];
3220
- const mapped = stack.slice(0, -1).map((im) => applyMagickClut(im, lut, state.channels));
3453
+ const mapped = yield* mapSteps(stack.slice(0, -1), function* (im) {
3454
+ return yield* applyMagickClutSteps(im, lut, state.channels, signal);
3455
+ });
3221
3456
  stack = mapped;
3222
3457
  }
3223
3458
  } else if (t === "-fx") {
3224
3459
  const expr = tokens[++i] ?? "u";
3225
3460
  if (stack.length > 0) {
3226
- stack = [applyMagickFx(stack, expr, state.channels)];
3461
+ stack = [yield* applyMagickFxSteps(stack, expr, state.channels, signal)];
3227
3462
  }
3228
3463
  } else if (t === "-shear") {
3229
3464
  const geom = tokens[++i] ?? "0x0";
3230
- stack = stack.map((im) => applyMagickShear(im, geom, state.background));
3465
+ stack = yield* mapSteps(stack, function* (im) {
3466
+ return yield* applyMagickShearSteps(im, geom, state.background, signal);
3467
+ });
3231
3468
  } else if (t === "-distort" || t === "+distort") {
3232
3469
  const method = tokens[++i] ?? "SRT";
3233
3470
  const args = tokens[++i] ?? "0";
3234
- stack = stack.map((im) => applyMagickDistort(im, method, args, state.background));
3471
+ stack = yield* mapSteps(stack, function* (im) {
3472
+ return yield* applyMagickDistortSteps(im, method, args, state.background, signal);
3473
+ });
3235
3474
  } else if (t === "-swirl") {
3236
3475
  const deg = Number(tokens[++i] ?? 0);
3237
- stack = stack.map((im) => applyMagickSwirl(im, deg, state.background));
3476
+ stack = yield* mapSteps(stack, function* (im) {
3477
+ return yield* applyMagickSwirlSteps(im, deg, state.background, signal);
3478
+ });
3238
3479
  } else if (t === "-implode") {
3239
3480
  const amt = Number(tokens[++i] ?? 0);
3240
- stack = stack.map((im) => applyMagickImplode(im, amt, state.background));
3481
+ stack = yield* mapSteps(stack, function* (im) {
3482
+ return yield* applyMagickImplodeSteps(im, amt, state.background, signal);
3483
+ });
3241
3484
  } else if (t === "-wave") {
3242
3485
  const geom = tokens[++i] ?? "5x50";
3243
- stack = stack.map((im) => applyMagickWave(im, geom, state.background));
3486
+ stack = yield* mapSteps(stack, function* (im) {
3487
+ return yield* applyMagickWaveSteps(im, geom, state.background, signal);
3488
+ });
3244
3489
  } else if (t === "-shadow") {
3245
3490
  const geom = tokens[++i] ?? "80x3+5+5";
3246
- stack = stack.map((im) => applyMagickShadow(im, geom, state.background));
3491
+ stack = yield* mapSteps(stack, function* (im) {
3492
+ return yield* applyMagickShadowSteps(im, geom, state.background, signal);
3493
+ });
3247
3494
  } else if (t === "-vignette") {
3248
3495
  const geom = tokens[++i] ?? "0x2";
3249
- stack = stack.map((im) => applyMagickVignette(im, geom, state.background));
3496
+ stack = yield* mapSteps(stack, function* (im) {
3497
+ return yield* applyMagickVignetteSteps(im, geom, state.background, signal);
3498
+ });
3250
3499
  } else if (t === "-sepia-tone") {
3251
3500
  const thresh = tokens[++i] ?? "80%";
3252
- stack = stack.map((im) => applyMagickSepiaTone(im, thresh));
3501
+ stack = yield* mapSteps(stack, function* (im) {
3502
+ return yield* applyMagickSepiaToneSteps(im, thresh, signal);
3503
+ });
3253
3504
  } else if (t === "-solarize") {
3254
3505
  const thresh = tokens[++i] ?? "50%";
3255
- stack = stack.map((im) => applyMagickSolarize(im, thresh));
3506
+ stack = yield* mapSteps(stack, function* (im) {
3507
+ return yield* applyMagickSolarizeSteps(im, thresh, signal);
3508
+ });
3256
3509
  } else if (t === "-posterize" || t === "-colors") {
3257
3510
  const lv = Number(tokens[++i] ?? 8);
3258
- stack = stack.map((im) => applyMagickPosterize(im, lv));
3511
+ stack = yield* mapSteps(stack, function* (im) {
3512
+ return yield* applyMagickPosterizeSteps(im, lv, signal);
3513
+ });
3259
3514
  } else if (t === "-dither" || t === "+dither") {
3260
3515
  if (t === "+dither") {
3261
3516
  state.dither = false;
@@ -3265,22 +3520,22 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3265
3520
  }
3266
3521
  } else if (t === "-edge" || t === "-canny") {
3267
3522
  i++;
3268
- stack = stack.map((im) => applyMagickConvolve3x3(im, [-1, -1, -1, -1, 8, -1, -1, -1, -1], 0));
3523
+ stack = yield* mapSteps(stack, function* (im) {
3524
+ return yield* applyMagickConvolve3x3Steps(im, [-1, -1, -1, -1, 8, -1, -1, -1, -1], 0, signal);
3525
+ });
3269
3526
  } else if (t === "-emboss") {
3270
3527
  i++;
3271
- stack = stack.map((im) => applyMagickConvolve3x3(im, [-2, -1, 0, -1, 1, 1, 0, 1, 2], 128));
3528
+ stack = yield* mapSteps(stack, function* (im) {
3529
+ return yield* applyMagickConvolve3x3Steps(im, [-2, -1, 0, -1, 1, 1, 0, 1, 2], 128, signal);
3530
+ });
3272
3531
  } else if (t === "-charcoal" || t === "-sketch") {
3273
3532
  i++;
3274
- stack = stack.map(
3275
- (im) => grayscaleImage(
3276
- negateImage(
3277
- applyMagickConvolve3x3(blurImage(im, 1), [-1, -1, -1, -1, 8, -1, -1, -1, -1], 0),
3278
- { alpha: false }
3279
- )
3280
- )
3281
- );
3533
+ stack = yield* mapSteps(stack, function* (im) {
3534
+ return grayscaleImage(negateImage(yield* applyMagickConvolve3x3Steps(blurImage(im, 1), [-1, -1, -1, -1, 8, -1, -1, -1, -1], 0, signal), { alpha: false }));
3535
+ });
3282
3536
  } else if (t === "+repage" || t === "-repage") {
3283
- if (t === "-repage") i++;
3537
+ if (t === "-repage")
3538
+ i++;
3284
3539
  } else if (t === "-resize" || t === "-scale" || t === "-sample" || t === "-thumbnail") {
3285
3540
  const geom = tokens[++i] ?? "100%";
3286
3541
  const k = t === "-sample" ? "nearest" : state.kernel;
@@ -3289,26 +3544,28 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3289
3544
  const geom = tokens[++i] ?? "100%";
3290
3545
  const nextStack = [];
3291
3546
  for (const im of stack) {
3547
+ if (++cooperativeWork % 65536 === 0)
3548
+ yield;
3292
3549
  nextStack.push(...applyMagickCropToStack(im, geom, state.gravity));
3293
3550
  }
3294
3551
  stack = nextStack;
3295
3552
  } else if (t === "-extent") {
3296
3553
  const geom = tokens[++i] ?? "100%";
3297
- stack = stack.map((im) => applyMagickExtent(im, geom, state));
3554
+ stack = yield* mapSteps(stack, function* (im) {
3555
+ return yield* applyMagickExtentSteps(im, geom, state, signal);
3556
+ });
3298
3557
  } else if (t === "-border") {
3299
3558
  const g = parseMagickGeometry(tokens[++i] ?? "0x0");
3300
3559
  const bw = Math.max(0, Math.round(g.width ?? 0));
3301
3560
  const bh = Math.max(0, Math.round(g.height ?? bw));
3302
- stack = stack.map(
3303
- (im) => extendImage(im, {
3304
- top: bh,
3305
- bottom: bh,
3306
- left: bw,
3307
- right: bw,
3308
- background: state.borderColor,
3309
- extendWith: "background"
3310
- })
3311
- );
3561
+ stack = stack.map((im) => extendImage(im, {
3562
+ top: bh,
3563
+ bottom: bh,
3564
+ left: bw,
3565
+ right: bw,
3566
+ background: state.borderColor,
3567
+ extendWith: "background"
3568
+ }));
3312
3569
  } else if (t === "-shave") {
3313
3570
  const g = parseMagickGeometry(tokens[++i] ?? "0x0");
3314
3571
  const sw = Math.max(0, Math.round(g.width ?? 0));
@@ -3347,11 +3604,16 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3347
3604
  const r = out[idx];
3348
3605
  const g = out[idx + 1];
3349
3606
  const b = out[idx + 2];
3350
- if (onlyGray && !(r === g && g === b)) continue;
3351
- if (ch.r) out[idx] = 255 - r;
3352
- if (ch.g) out[idx + 1] = 255 - g;
3353
- if (ch.b) out[idx + 2] = 255 - b;
3354
- if (ch.a) out[idx + 3] = 255 - out[idx + 3];
3607
+ if (onlyGray && !(r === g && g === b))
3608
+ continue;
3609
+ if (ch.r)
3610
+ out[idx] = 255 - r;
3611
+ if (ch.g)
3612
+ out[idx + 1] = 255 - g;
3613
+ if (ch.b)
3614
+ out[idx + 2] = 255 - b;
3615
+ if (ch.a)
3616
+ out[idx + 3] = 255 - out[idx + 3];
3355
3617
  }
3356
3618
  return { ...im, data: out };
3357
3619
  });
@@ -3388,8 +3650,10 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3388
3650
  for (let idx = 0; idx < out.length; idx += 4) {
3389
3651
  for (let c = 0; c < 4; c++) {
3390
3652
  const v = out[idx + c];
3391
- if (v < mins[c]) mins[c] = v;
3392
- if (v > maxs[c]) maxs[c] = v;
3653
+ if (v < mins[c])
3654
+ mins[c] = v;
3655
+ if (v > maxs[c])
3656
+ maxs[c] = v;
3393
3657
  }
3394
3658
  }
3395
3659
  if (!indep) {
@@ -3401,7 +3665,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3401
3665
  const active = [ch.r, ch.g, ch.b, ch.a];
3402
3666
  for (let idx = 0; idx < out.length; idx += 4) {
3403
3667
  for (let c = 0; c < 4; c++) {
3404
- if (!active[c]) continue;
3668
+ if (!active[c])
3669
+ continue;
3405
3670
  const range = maxs[c] - mins[c];
3406
3671
  if (range > 0) {
3407
3672
  out[idx + c] = clampByteVal((out[idx + c] - mins[c]) / range * 255);
@@ -3423,7 +3688,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3423
3688
  const highTarget = isPct ? (100 - wVal) / 100 * nPix : nPix - wVal;
3424
3689
  for (let c = 0; c < 3; c++) {
3425
3690
  const hist = new Uint32Array(256);
3426
- for (let idx = c; idx < out.length; idx += 4) hist[out[idx]]++;
3691
+ for (let idx = c; idx < out.length; idx += 4)
3692
+ hist[out[idx]]++;
3427
3693
  let lowBin = 0;
3428
3694
  let acc = 0;
3429
3695
  for (let b = 0; b < 256; b++) {
@@ -3465,7 +3731,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3465
3731
  for (let x = 0; x < im.width; x++) {
3466
3732
  const topLeft = y < bw || x < bw;
3467
3733
  const botRight = y >= im.height - bw || x >= im.width - bw;
3468
- if (!topLeft && !botRight) continue;
3734
+ if (!topLeft && !botRight)
3735
+ continue;
3469
3736
  const lighten = raised ? topLeft : botRight;
3470
3737
  const idx = (y * im.width + x) * 4;
3471
3738
  for (let c = 0; c < 3; c++) {
@@ -3479,16 +3746,14 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3479
3746
  const g = parseMagickGeometry(tokens[++i] ?? "4x4");
3480
3747
  const fw = Math.max(0, Math.round(g.width ?? 4));
3481
3748
  const fh = Math.max(0, Math.round(g.height ?? fw));
3482
- stack = stack.map(
3483
- (im) => extendImage(im, {
3484
- top: fh,
3485
- bottom: fh,
3486
- left: fw,
3487
- right: fw,
3488
- background: state.borderColor,
3489
- extendWith: "background"
3490
- })
3491
- );
3749
+ stack = stack.map((im) => extendImage(im, {
3750
+ top: fh,
3751
+ bottom: fh,
3752
+ left: fw,
3753
+ right: fw,
3754
+ background: state.borderColor,
3755
+ extendWith: "background"
3756
+ }));
3492
3757
  } else if (t === "-deskew") {
3493
3758
  i++;
3494
3759
  } else if (t === "-auto-gamma") {
@@ -3497,7 +3762,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3497
3762
  const numCh = im.hasAlpha ? 4 : 3;
3498
3763
  let sum = 0;
3499
3764
  for (let idx = 0; idx < out.length; idx += 4) {
3500
- for (let c = 0; c < numCh; c++) sum += out[idx + c];
3765
+ for (let c = 0; c < numCh; c++)
3766
+ sum += out[idx + c];
3501
3767
  }
3502
3768
  const mean = sum / Math.max(1, im.width * im.height * numCh * 255);
3503
3769
  if (mean > 0 && mean < 1) {
@@ -3535,7 +3801,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3535
3801
  const parts = raw.split(",");
3536
3802
  const anyPct = raw.includes("%");
3537
3803
  const parsePt = (p, def) => {
3538
- if (!p || p.length === 0) return def;
3804
+ if (!p || p.length === 0)
3805
+ return def;
3539
3806
  if (p.endsWith("%") || anyPct) {
3540
3807
  return parseFloat(p) / 100 * 255;
3541
3808
  }
@@ -3607,14 +3874,20 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3607
3874
  kernelSpec = tokens[++i];
3608
3875
  }
3609
3876
  if (method.includes("convolve") || method.includes("correlate")) {
3610
- stack = stack.map((im) => applyMagickCustomConvolve(im, kernelSpec));
3877
+ stack = yield* mapSteps(stack, function* (im) {
3878
+ return yield* applyMagickCustomConvolveSteps(im, kernelSpec, signal);
3879
+ });
3611
3880
  } else {
3612
- stack = stack.map((im) => applyMagickMorphology4Ch(im, method, kernelSpec));
3881
+ stack = yield* mapSteps(stack, function* (im) {
3882
+ return yield* applyMagickMorphology4ChSteps(im, method, kernelSpec, signal);
3883
+ });
3613
3884
  }
3614
3885
  } else if (t === "-statistic") {
3615
3886
  const statType = (tokens[++i] ?? "median").toLowerCase();
3616
3887
  const geom = tokens[++i] ?? "3x3";
3617
- stack = stack.map((im) => applyMagickMorphology4Ch(im, statType, geom));
3888
+ stack = yield* mapSteps(stack, function* (im) {
3889
+ return yield* applyMagickMorphology4ChSteps(im, statType, geom, signal);
3890
+ });
3618
3891
  } else if (t === "-alpha") {
3619
3892
  const mode = (tokens[++i] ?? "on").toLowerCase();
3620
3893
  if (mode === "remove") {
@@ -3622,22 +3895,22 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3622
3895
  } else if (mode === "off" || mode === "deactivate" || mode === "opaque") {
3623
3896
  stack = stack.map((im) => {
3624
3897
  const out = new Uint8Array(im.data);
3625
- for (let idx = 3; idx < out.length; idx += 4) out[idx] = 255;
3898
+ for (let idx = 3; idx < out.length; idx += 4)
3899
+ out[idx] = 255;
3626
3900
  return { ...im, data: out, hasAlpha: mode === "opaque" };
3627
3901
  });
3628
3902
  } else if (mode === "transparent") {
3629
3903
  stack = stack.map((im) => {
3630
3904
  const out = new Uint8Array(im.data);
3631
- for (let idx = 3; idx < out.length; idx += 4) out[idx] = 0;
3905
+ for (let idx = 3; idx < out.length; idx += 4)
3906
+ out[idx] = 0;
3632
3907
  return { ...im, data: out, hasAlpha: true };
3633
3908
  });
3634
3909
  } else if (mode === "copy" || mode === "shape") {
3635
3910
  stack = stack.map((im) => {
3636
3911
  const out = new Uint8Array(im.data);
3637
3912
  for (let idx = 0; idx < out.length; idx += 4) {
3638
- const inten = clampByteVal(
3639
- 0.212656 * out[idx] + 0.715158 * out[idx + 1] + 0.072186 * out[idx + 2]
3640
- );
3913
+ const inten = clampByteVal(0.212656 * out[idx] + 0.715158 * out[idx + 1] + 0.072186 * out[idx + 2]);
3641
3914
  if (mode === "shape") {
3642
3915
  out[idx] = state.background.r;
3643
3916
  out[idx + 1] = state.background.g;
@@ -3655,17 +3928,19 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3655
3928
  } else if (t === "-separate") {
3656
3929
  const nextStack = [];
3657
3930
  for (const im of stack) {
3931
+ if (++cooperativeWork % 65536 === 0)
3932
+ yield;
3658
3933
  if (state.channelExplicit) {
3659
- if (state.channels.r) nextStack.push(extractChannelImage(im, 0));
3660
- if (state.channels.g) nextStack.push(extractChannelImage(im, 1));
3661
- if (state.channels.b) nextStack.push(extractChannelImage(im, 2));
3662
- if (state.channels.a) nextStack.push(extractChannelImage(ensureAlphaImage(im, 1), 3));
3934
+ if (state.channels.r)
3935
+ nextStack.push(extractChannelImage(im, 0));
3936
+ if (state.channels.g)
3937
+ nextStack.push(extractChannelImage(im, 1));
3938
+ if (state.channels.b)
3939
+ nextStack.push(extractChannelImage(im, 2));
3940
+ if (state.channels.a)
3941
+ nextStack.push(extractChannelImage(ensureAlphaImage(im, 1), 3));
3663
3942
  } else {
3664
- nextStack.push(
3665
- extractChannelImage(im, 0),
3666
- extractChannelImage(im, 1),
3667
- extractChannelImage(im, 2)
3668
- );
3943
+ nextStack.push(extractChannelImage(im, 0), extractChannelImage(im, 1), extractChannelImage(im, 2));
3669
3944
  if (im.hasAlpha) {
3670
3945
  nextStack.push(extractChannelImage(ensureAlphaImage(im, 1), 3));
3671
3946
  }
@@ -3680,6 +3955,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3680
3955
  const aIm = stack[3];
3681
3956
  const out = new Uint8Array(rIm.width * rIm.height * 4);
3682
3957
  for (let p = 0; p < out.length; p += 4) {
3958
+ if (++cooperativeWork % 65536 === 0)
3959
+ yield;
3683
3960
  out[p] = rIm.data[p];
3684
3961
  out[p + 1] = gIm.data[p];
3685
3962
  out[p + 2] = bIm.data[p];
@@ -3689,19 +3966,26 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3689
3966
  }
3690
3967
  } else if (t === "-draw") {
3691
3968
  const drawSpec = tokens[++i] ?? "";
3692
- stack = stack.map((im) => applyMagickDraw(im, drawSpec, state));
3969
+ stack = yield* mapSteps(stack, function* (im) {
3970
+ return yield* applyMagickDrawSteps(im, drawSpec, state, signal);
3971
+ });
3693
3972
  } else if (t === "-annotate") {
3694
3973
  const offsetOrText = tokens[++i] ?? "+0+0";
3695
3974
  const hasExplicitOffset = /^[+-]\d/.test(offsetOrText) || /^\d+x\d+/.test(offsetOrText);
3696
3975
  const offset = hasExplicitOffset ? offsetOrText : "+0+0";
3697
3976
  const text = hasExplicitOffset ? tokens[++i] ?? "" : offsetOrText;
3698
- stack = stack.map((im) => applyMagickAnnotate(im, offset, text, state));
3977
+ stack = yield* mapSteps(stack, function* (im) {
3978
+ return yield* applyMagickAnnotateSteps(im, offset, text, state, signal);
3979
+ });
3699
3980
  } else if (t === "+clone" || t === "-clone") {
3700
3981
  const sourcePool = stack.length > 0 ? stack : parentStack;
3701
3982
  const spec = t === "+clone" ? "-1" : tokens[++i] ?? "-1";
3702
3983
  for (const idx of parseMagickIndexSpec(spec, sourcePool.length)) {
3984
+ if (++cooperativeWork % 65536 === 0)
3985
+ yield;
3703
3986
  const chosen = sourcePool[idx];
3704
- if (chosen) stack.push({ ...chosen, data: new Uint8Array(chosen.data) });
3987
+ if (chosen)
3988
+ stack.push({ ...chosen, data: new Uint8Array(chosen.data) });
3705
3989
  }
3706
3990
  } else if (t === "-duplicate" || t === "+duplicate") {
3707
3991
  let count = 1;
@@ -3722,9 +4006,14 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3722
4006
  const sourcePool = stack.length > 0 ? stack : parentStack;
3723
4007
  const indices = parseMagickIndexSpec(idxSpec, sourcePool.length);
3724
4008
  for (let k = 0; k < count; k++) {
4009
+ if (++cooperativeWork % 65536 === 0)
4010
+ yield;
3725
4011
  for (const idx of indices) {
4012
+ if (++cooperativeWork % 65536 === 0)
4013
+ yield;
3726
4014
  const chosen = sourcePool[idx];
3727
- if (chosen) stack.push({ ...chosen, data: new Uint8Array(chosen.data) });
4015
+ if (chosen)
4016
+ stack.push({ ...chosen, data: new Uint8Array(chosen.data) });
3728
4017
  }
3729
4018
  }
3730
4019
  } else if (t === "+insert" || t === "-insert") {
@@ -3759,7 +4048,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3759
4048
  } else if (t === "-append" || t === "+append") {
3760
4049
  stack = [appendStackImages(stack, t === "-append", state)];
3761
4050
  } else if (t === "-flatten" || t === "-mosaic" || t === "-layers" && ["flatten", "merge", "mosaic"].includes((tokens[i + 1] ?? "").toLowerCase())) {
3762
- if (t === "-layers") i++;
4051
+ if (t === "-layers")
4052
+ i++;
3763
4053
  if (stack.length > 0) {
3764
4054
  const maxW = Math.max(...stack.map((im) => im.width));
3765
4055
  const maxH = Math.max(...stack.map((im) => im.height));
@@ -3782,14 +4072,7 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3782
4072
  gy = g.y;
3783
4073
  }
3784
4074
  const grav = resolveGravityOffset(base.width - overlay.width, base.height - overlay.height, state.gravity);
3785
- const composed = applyMagickCompositeLayer(
3786
- base,
3787
- overlay,
3788
- state.composeRaw,
3789
- grav.left + gx,
3790
- grav.top + gy,
3791
- state.composeArgs
3792
- );
4075
+ const composed = yield* applyMagickCompositeLayerSteps(base, overlay, state.composeRaw, grav.left + gx, grav.top + gy, state.composeArgs, signal);
3793
4076
  stack = [composed, ...stack.slice(2)];
3794
4077
  }
3795
4078
  } else {
@@ -3802,10 +4085,8 @@ function evaluatePipelineTokens(tokens, files, state, parentStack = [], stdinByt
3802
4085
  }
3803
4086
  return stack;
3804
4087
  }
3805
- async function runConvertCli(argv, files, stdinBytes) {
3806
- return runConvertCliSync(argv, files, stdinBytes);
3807
- }
3808
- function runConvertCliSync(argv, files, stdinBytes) {
4088
+ function* runConvertCliSteps(argv, files, stdinBytes, signal) {
4089
+ let cooperativeWork = 63;
3809
4090
  if (argv.length === 0 || argv.includes("--help") || argv.includes("-help") || argv.includes("-h")) {
3810
4091
  return {
3811
4092
  exitCode: 0,
@@ -3824,7 +4105,7 @@ function runConvertCliSync(argv, files, stdinBytes) {
3824
4105
  const pipelineTokens = argv.slice(0, -1);
3825
4106
  const state = createDefaultState();
3826
4107
  try {
3827
- const stack = evaluatePipelineTokens(pipelineTokens, files, state, [], stdinBytes);
4108
+ const stack = yield* evaluatePipelineTokensSteps(pipelineTokens, files, state, [], stdinBytes, signal);
3828
4109
  if (stack.length === 0) {
3829
4110
  return {
3830
4111
  exitCode: 1,
@@ -3860,6 +4141,8 @@ function runConvertCliSync(argv, files, stdinBytes) {
3860
4141
  const { format, path: outPath } = inferOutputFormat(outSpec, "png");
3861
4142
  if (stack.length > 1 && (/%0?\d*d/.test(outPath) || !state.adjoin)) {
3862
4143
  for (let idx = 0; idx < stack.length; idx++) {
4144
+ if (++cooperativeWork % 64 === 0)
4145
+ yield;
3863
4146
  const framePath = formatSceneOutputPath(outPath, idx);
3864
4147
  const { data: frameBytes } = encodeImage(stack[idx], { format, quality: state.quality });
3865
4148
  files.set(framePath, frameBytes);
@@ -3873,6 +4156,8 @@ function runConvertCliSync(argv, files, stdinBytes) {
3873
4156
  const fh = stack[0].height;
3874
4157
  const combined = new Uint8Array(fw * fh * stack.length * 4);
3875
4158
  for (let idx = 0; idx < stack.length; idx++) {
4159
+ if (++cooperativeWork % 64 === 0)
4160
+ yield;
3876
4161
  const frame = stack[idx].width === fw && stack[idx].height === fh ? stack[idx] : applyMagickResize(stack[idx], `${fw}x${fh}!`, state.kernel);
3877
4162
  combined.set(frame.data, idx * fw * fh * 4);
3878
4163
  }
@@ -3910,10 +4195,19 @@ function runConvertCliSync(argv, files, stdinBytes) {
3910
4195
  };
3911
4196
  }
3912
4197
  }
3913
- async function runMogrifyCli(argv, files) {
3914
- return runMogrifyCliSync(argv, files);
4198
+ async function runConvertCli(argv, files, stdinBytes, signal) {
4199
+ return drainSteps(runConvertCliSteps(argv, files, stdinBytes, signal), signal);
4200
+ }
4201
+ function runConvertCliSync(argv, files, stdinBytes, signal) {
4202
+ const steps = runConvertCliSteps(argv, files, stdinBytes, signal);
4203
+ let next = steps.next();
4204
+ while (!next.done) {
4205
+ next = steps.next();
4206
+ }
4207
+ return next.value;
3915
4208
  }
3916
- function runMogrifyCliSync(argv, files) {
4209
+ function* runMogrifyCliSteps(argv, files, _stdinBytes, signal) {
4210
+ let cooperativeWork = 63;
3917
4211
  let outFormatExt;
3918
4212
  let outDir;
3919
4213
  const opTokens = [];
@@ -4004,6 +4298,8 @@ function runMogrifyCliSync(argv, files) {
4004
4298
  "-sketch"
4005
4299
  ]);
4006
4300
  for (let i = 0; i < argv.length; i++) {
4301
+ if (++cooperativeWork % 64 === 0)
4302
+ yield;
4007
4303
  const t = argv[i];
4008
4304
  if (t === "-format") {
4009
4305
  outFormatExt = (argv[++i] ?? "png").replace(/^\./, "").toLowerCase();
@@ -4031,6 +4327,8 @@ function runMogrifyCliSync(argv, files) {
4031
4327
  }
4032
4328
  }
4033
4329
  for (const target of targets) {
4330
+ if (++cooperativeWork % 64 === 0)
4331
+ yield;
4034
4332
  if (!files.has(target)) {
4035
4333
  return {
4036
4334
  exitCode: 1,
@@ -4045,18 +4343,30 @@ function runMogrifyCliSync(argv, files) {
4045
4343
  const targetExt = outFormatExt ?? origExt;
4046
4344
  const destDir = outDir ? outDir.replace(/\/+$/, "") : target.slice(0, Math.max(0, target.lastIndexOf("/")));
4047
4345
  const destPath = outFormatExt || outDir ? `${destDir ? destDir + "/" : ""}${stem}.${targetExt}` : target;
4048
- const res = runConvertCliSync([...readSettings, target, ...opTokens, destPath], files);
4049
- if (res.exitCode !== 0) return res;
4346
+ const res = yield* runConvertCliSteps([...readSettings, target, ...opTokens, destPath], files, void 0, signal);
4347
+ if (res.exitCode !== 0)
4348
+ return res;
4050
4349
  }
4051
4350
  return { exitCode: 0, stdout: "", stderr: "" };
4052
4351
  }
4053
- async function runCompositeCli(argv, files, stdinBytes) {
4054
- return runCompositeCliSync(argv, files, stdinBytes);
4352
+ async function runMogrifyCli(argv, files, _stdinBytes, signal) {
4353
+ return drainSteps(runMogrifyCliSteps(argv, files, _stdinBytes, signal), signal);
4055
4354
  }
4056
- function runCompositeCliSync(argv, files, stdinBytes) {
4355
+ function runMogrifyCliSync(argv, files, _stdinBytes, signal) {
4356
+ const steps = runMogrifyCliSteps(argv, files, _stdinBytes, signal);
4357
+ let next = steps.next();
4358
+ while (!next.done) {
4359
+ next = steps.next();
4360
+ }
4361
+ return next.value;
4362
+ }
4363
+ function* runCompositeCliSteps(argv, files, stdinBytes, signal) {
4364
+ let cooperativeWork = 63;
4057
4365
  const options = [];
4058
4366
  const operands = [];
4059
4367
  for (let i = 0; i < argv.length; i++) {
4368
+ if (++cooperativeWork % 64 === 0)
4369
+ yield;
4060
4370
  const t = argv[i];
4061
4371
  if (t === "-gravity" || t === "-geometry" || t === "-compose" || t === "-background" || t === "-quality" || t === "-define") {
4062
4372
  options.push(t, argv[++i] ?? "");
@@ -4080,7 +4390,18 @@ function runCompositeCliSync(argv, files, stdinBytes) {
4080
4390
  const overlay = operands[0];
4081
4391
  const base = operands[1];
4082
4392
  const out = operands[operands.length - 1];
4083
- return runConvertCliSync([base, overlay, ...options, "-composite", out], files, stdinBytes);
4393
+ return yield* runConvertCliSteps([base, overlay, ...options, "-composite", out], files, stdinBytes, signal);
4394
+ }
4395
+ async function runCompositeCli(argv, files, stdinBytes, signal) {
4396
+ return drainSteps(runCompositeCliSteps(argv, files, stdinBytes, signal), signal);
4397
+ }
4398
+ function runCompositeCliSync(argv, files, stdinBytes, signal) {
4399
+ const steps = runCompositeCliSteps(argv, files, stdinBytes, signal);
4400
+ let next = steps.next();
4401
+ while (!next.done) {
4402
+ next = steps.next();
4403
+ }
4404
+ return next.value;
4084
4405
  }
4085
4406
  function formatMetricNum(n) {
4086
4407
  if (!Number.isFinite(n)) return "inf";
@@ -4088,10 +4409,8 @@ function formatMetricNum(n) {
4088
4409
  const fixed = n.toFixed(6).replace(/\.?0+$/, "");
4089
4410
  return fixed === "-0" ? "0" : fixed;
4090
4411
  }
4091
- async function runCompareCli(argv, files, stdinBytes) {
4092
- return runCompareCliSync(argv, files, stdinBytes);
4093
- }
4094
- function runCompareCliSync(argv, files, stdinBytes) {
4412
+ function* runCompareCliSteps(argv, files, stdinBytes, signal) {
4413
+ let cooperativeWork = 63;
4095
4414
  const state = createDefaultState();
4096
4415
  state.fuzz = 0;
4097
4416
  let metric = "rmse";
@@ -4101,6 +4420,8 @@ function runCompareCliSync(argv, files, stdinBytes) {
4101
4420
  let dissimilarityThreshold;
4102
4421
  const operands = [];
4103
4422
  for (let i = 0; i < argv.length; i++) {
4423
+ if (++cooperativeWork % 64 === 0)
4424
+ yield;
4104
4425
  const t = argv[i];
4105
4426
  if (t === "--help" || t === "-help" || t === "-h") {
4106
4427
  return {
@@ -4119,7 +4440,8 @@ function runCompareCliSync(argv, files, stdinBytes) {
4119
4440
  lowlightColor = parseColor2(argv[++i] ?? "#ffffff");
4120
4441
  } else if (t === "-compose") {
4121
4442
  const cm = (argv[++i] ?? "over").toLowerCase();
4122
- if (cm === "src" || cm === "source" || cm === "copy") composeSrc = true;
4443
+ if (cm === "src" || cm === "source" || cm === "copy")
4444
+ composeSrc = true;
4123
4445
  } else if (t === "-dissimilarity-threshold") {
4124
4446
  dissimilarityThreshold = Number(argv[++i] ?? 1);
4125
4447
  } else if (t === "-density") {
@@ -4128,7 +4450,8 @@ function runCompareCliSync(argv, files, stdinBytes) {
4128
4450
  } else if (t === "-quality") {
4129
4451
  state.quality = Math.max(1, Math.min(100, Number(argv[++i] ?? 92)));
4130
4452
  } else if (t.startsWith("-") && t.length > 1) {
4131
- if (t === "-format" || t === "-alpha" || t === "-channel") i++;
4453
+ if (t === "-format" || t === "-alpha" || t === "-channel")
4454
+ i++;
4132
4455
  } else {
4133
4456
  operands.push(t);
4134
4457
  }
@@ -4185,7 +4508,11 @@ function runCompareCliSync(argv, files, stdinBytes) {
4185
4508
  let sumLumA = 0;
4186
4509
  let sumLumB = 0;
4187
4510
  for (let y = 0; y < height; y++) {
4511
+ if (++cooperativeWork % 64 === 0)
4512
+ yield;
4188
4513
  for (let x = 0; x < width; x++) {
4514
+ if (++cooperativeWork % 64 === 0)
4515
+ yield;
4189
4516
  const pIdx = y * width + x;
4190
4517
  const outOff = pIdx * 4;
4191
4518
  const inBoundsA = x < imgA.width && y < imgA.height;
@@ -4240,7 +4567,8 @@ function runCompareCliSync(argv, files, stdinBytes) {
4240
4567
  sumAbs += dr + dg + db;
4241
4568
  sumSq += dr * dr + dg * dg + db * db;
4242
4569
  }
4243
- if (maxDelta > maxAbs) maxAbs = maxDelta;
4570
+ if (maxDelta > maxAbs)
4571
+ maxAbs = maxDelta;
4244
4572
  const lA = (0.299 * rA + 0.587 * gA + 0.114 * bA) / 255;
4245
4573
  const lB = (0.299 * rB + 0.587 * gB + 0.114 * bB) / 255;
4246
4574
  lumA[pIdx] = lA;
@@ -4260,6 +4588,8 @@ function runCompareCliSync(argv, files, stdinBytes) {
4260
4588
  let varB = 0;
4261
4589
  let covAB = 0;
4262
4590
  for (let i = 0; i < totalPixels; i++) {
4591
+ if (++cooperativeWork % 64 === 0)
4592
+ yield;
4263
4593
  const dA = lumA[i] - muA;
4264
4594
  const dB = lumB[i] - muB;
4265
4595
  varA += dA * dA;
@@ -4337,10 +4667,19 @@ function runCompareCliSync(argv, files, stdinBytes) {
4337
4667
  `
4338
4668
  };
4339
4669
  }
4340
- async function runMontageCli(argv, files, stdinBytes) {
4341
- return runMontageCliSync(argv, files, stdinBytes);
4670
+ async function runCompareCli(argv, files, stdinBytes, signal) {
4671
+ return drainSteps(runCompareCliSteps(argv, files, stdinBytes, signal), signal);
4342
4672
  }
4343
- function runMontageCliSync(argv, files, stdinBytes) {
4673
+ function runCompareCliSync(argv, files, stdinBytes, signal) {
4674
+ const steps = runCompareCliSteps(argv, files, stdinBytes, signal);
4675
+ let next = steps.next();
4676
+ while (!next.done) {
4677
+ next = steps.next();
4678
+ }
4679
+ return next.value;
4680
+ }
4681
+ function* runMontageCliSteps(argv, files, stdinBytes, signal) {
4682
+ let cooperativeWork = 63;
4344
4683
  const state = createDefaultState();
4345
4684
  let tileCols;
4346
4685
  let tileRows;
@@ -4351,6 +4690,8 @@ function runMontageCliSync(argv, files, stdinBytes) {
4351
4690
  let borderW = 0;
4352
4691
  const operands = [];
4353
4692
  for (let i = 0; i < argv.length; i++) {
4693
+ if (++cooperativeWork % 64 === 0)
4694
+ yield;
4354
4695
  const t = argv[i];
4355
4696
  if (t === "-tile") {
4356
4697
  const g = parseMagickGeometry(argv[++i] ?? "2x2");
@@ -4391,6 +4732,7 @@ function runMontageCliSync(argv, files, stdinBytes) {
4391
4732
  const inPaths = operands.slice(0, -1);
4392
4733
  const images = [];
4393
4734
  for (const p of inPaths) {
4735
+ yield;
4394
4736
  let loadedList;
4395
4737
  try {
4396
4738
  loadedList = parseInputOperands(p, files, state, stdinBytes);
@@ -4411,6 +4753,8 @@ function runMontageCliSync(argv, files, stdinBytes) {
4411
4753
  };
4412
4754
  }
4413
4755
  for (const loaded of loadedList) {
4756
+ if (++cooperativeWork % 64 === 0)
4757
+ yield;
4414
4758
  let thumb = loaded;
4415
4759
  if (cellW !== void 0 || cellH !== void 0) {
4416
4760
  const geomSpec = `${cellW ?? ""}${cellH !== void 0 ? "x" + cellH : ""}`;
@@ -4441,9 +4785,12 @@ function runMontageCliSync(argv, files, stdinBytes) {
4441
4785
  const canvas = createSolidRgbaImage(canvasW, canvasH, state.background);
4442
4786
  const layers = [];
4443
4787
  for (let idx = 0; idx < images.length; idx++) {
4788
+ if (++cooperativeWork % 64 === 0)
4789
+ yield;
4444
4790
  const col = idx % cols;
4445
4791
  const row = Math.floor(idx / cols);
4446
- if (row >= rows) break;
4792
+ if (row >= rows)
4793
+ break;
4447
4794
  const im = images[idx];
4448
4795
  const cellX = col * slotW + padX;
4449
4796
  const cellY = row * slotH + padY;
@@ -4459,32 +4806,52 @@ function runMontageCliSync(argv, files, stdinBytes) {
4459
4806
  files.set(outPath, encoded);
4460
4807
  return { exitCode: 0, stdout: "", stderr: "" };
4461
4808
  }
4462
- async function runMagickCli(argv, files, stdinBytes) {
4463
- return runMagickCliSync(argv, files, stdinBytes);
4809
+ async function runMontageCli(argv, files, stdinBytes, signal) {
4810
+ return drainSteps(runMontageCliSteps(argv, files, stdinBytes, signal), signal);
4811
+ }
4812
+ function runMontageCliSync(argv, files, stdinBytes, signal) {
4813
+ const steps = runMontageCliSteps(argv, files, stdinBytes, signal);
4814
+ let next = steps.next();
4815
+ while (!next.done) {
4816
+ next = steps.next();
4817
+ }
4818
+ return next.value;
4464
4819
  }
4465
- function runMagickCliSync(argv, files, stdinBytes) {
4820
+ function* runMagickCliSteps(argv, files, stdinBytes, signal) {
4466
4821
  const sub = argv[0];
4467
4822
  if (sub === "identify") {
4468
- return runIdentifyCliSync(argv.slice(1), files, stdinBytes);
4823
+ return yield* runIdentifyCliSteps(argv.slice(1), files, stdinBytes, signal);
4469
4824
  }
4470
4825
  if (sub === "mogrify") {
4471
- return runMogrifyCliSync(argv.slice(1), files);
4826
+ return yield* runMogrifyCliSteps(argv.slice(1), files, void 0, signal);
4472
4827
  }
4473
4828
  if (sub === "composite") {
4474
- return runCompositeCliSync(argv.slice(1), files, stdinBytes);
4829
+ return yield* runCompositeCliSteps(argv.slice(1), files, stdinBytes, signal);
4475
4830
  }
4476
4831
  if (sub === "montage") {
4477
- return runMontageCliSync(argv.slice(1), files, stdinBytes);
4832
+ return yield* runMontageCliSteps(argv.slice(1), files, stdinBytes, signal);
4478
4833
  }
4479
4834
  if (sub === "compare") {
4480
- return runCompareCliSync(argv.slice(1), files, stdinBytes);
4835
+ return yield* runCompareCliSteps(argv.slice(1), files, stdinBytes, signal);
4481
4836
  }
4482
4837
  if (sub === "convert") {
4483
- return runConvertCliSync(argv.slice(1), files, stdinBytes);
4838
+ return yield* runConvertCliSteps(argv.slice(1), files, stdinBytes, signal);
4484
4839
  }
4485
- return runConvertCliSync(argv, files, stdinBytes);
4840
+ return yield* runConvertCliSteps(argv, files, stdinBytes, signal);
4841
+ }
4842
+ async function runMagickCli(argv, files, stdinBytes, signal) {
4843
+ return drainSteps(runMagickCliSteps(argv, files, stdinBytes, signal), signal);
4844
+ }
4845
+ function runMagickCliSync(argv, files, stdinBytes, signal) {
4846
+ const steps = runMagickCliSteps(argv, files, stdinBytes, signal);
4847
+ let next = steps.next();
4848
+ while (!next.done) {
4849
+ next = steps.next();
4850
+ }
4851
+ return next.value;
4486
4852
  }
4487
4853
  async function executeVfsMagickTool(context, runner) {
4854
+ let cooperativeWork = 63;
4488
4855
  const invocation = createOutputOperation(context, { write: async () => {
4489
4856
  } });
4490
4857
  try {
@@ -4495,6 +4862,7 @@ async function executeVfsMagickTool(context, runner) {
4495
4862
  let needsStdin = false;
4496
4863
  const hasOutputOperand = runner !== runIdentifyCli && !(runner === runMagickCli && argv[0] === "identify");
4497
4864
  for (const [index, token] of argv.entries()) {
4865
+ if (++cooperativeWork % 64 === 0) await yieldTurn(context.signal);
4498
4866
  if (token === "-" || token.endsWith(":-")) {
4499
4867
  if (!hasOutputOperand || index < argv.length - 1) needsStdin = true;
4500
4868
  continue;
@@ -4522,18 +4890,21 @@ async function executeVfsMagickTool(context, runner) {
4522
4890
  const chunks = [];
4523
4891
  let total = 0;
4524
4892
  for await (const chunk of readBytes(context.stdin, invocation.signal)) {
4893
+ if (++cooperativeWork % 64 === 0) await yieldTurn(context.signal);
4525
4894
  chunks.push(chunk);
4526
4895
  total += chunk.byteLength;
4527
4896
  }
4528
4897
  stdinBytes = new Uint8Array(total);
4529
4898
  let off = 0;
4530
4899
  for (const chunk of chunks) {
4900
+ if (++cooperativeWork % 64 === 0) await yieldTurn(context.signal);
4531
4901
  stdinBytes.set(chunk, off);
4532
4902
  off += chunk.byteLength;
4533
4903
  }
4534
4904
  }
4905
+ context.inputBudget?.check(0);
4535
4906
  const existingSnap = new Map(vfsFiles);
4536
- const res = await runner(argv, vfsFiles, stdinBytes);
4907
+ const res = await runner(argv, vfsFiles, stdinBytes, invocation.signal);
4537
4908
  if (res.stderr) {
4538
4909
  await writeBytes(context.stderr, new TextEncoder().encode(res.stderr), invocation.signal);
4539
4910
  }
@@ -4545,6 +4916,7 @@ async function executeVfsMagickTool(context, runner) {
4545
4916
  await writeBytes(stdout.output, new TextEncoder().encode(res.stdout), invocation.signal);
4546
4917
  }
4547
4918
  for (const [key, val] of vfsFiles.entries()) {
4919
+ if (++cooperativeWork % 64 === 0) await yieldTurn(context.signal);
4548
4920
  if (existingSnap.get(key) !== val) {
4549
4921
  const abs = resolveVfsPath(key);
4550
4922
  const parentDir = abs.slice(0, abs.lastIndexOf("/")) || "/";
@@ -4560,79 +4932,100 @@ async function executeVfsMagickTool(context, runner) {
4560
4932
  await invocation.close();
4561
4933
  }
4562
4934
  }
4563
- function createMagickCommand(_options = {}) {
4935
+ function createMagickCommand(options = {}) {
4936
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4564
4937
  return Object.freeze({
4565
4938
  name: "magick",
4566
4939
  runtimeIdentity: commandRuntimeIdentity,
4567
4940
  description: "ImageMagick v7 image processor powered by @poe-code/image-ast",
4568
4941
  execute(context) {
4569
- return executeVfsMagickTool(context, runMagickCli);
4942
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
4943
+ return executeVfsMagickTool(context2, runMagickCli);
4944
+ });
4570
4945
  }
4571
4946
  });
4572
4947
  }
4573
4948
  var magickCommand = createMagickCommand();
4574
- function createConvertCommand(_options = {}) {
4949
+ function createConvertCommand(options = {}) {
4950
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4575
4951
  return Object.freeze({
4576
4952
  name: "convert",
4577
4953
  runtimeIdentity: commandRuntimeIdentity,
4578
4954
  description: "ImageMagick convert pipeline powered by @poe-code/image-ast",
4579
4955
  execute(context) {
4580
- return executeVfsMagickTool(context, runConvertCli);
4956
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
4957
+ return executeVfsMagickTool(context2, runConvertCli);
4958
+ });
4581
4959
  }
4582
4960
  });
4583
4961
  }
4584
4962
  var convertCommand = createConvertCommand();
4585
- function createMogrifyCommand(_options = {}) {
4963
+ function createMogrifyCommand(options = {}) {
4964
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4586
4965
  return Object.freeze({
4587
4966
  name: "mogrify",
4588
4967
  runtimeIdentity: commandRuntimeIdentity,
4589
4968
  description: "ImageMagick in-place batch image processor powered by @poe-code/image-ast",
4590
4969
  execute(context) {
4591
- return executeVfsMagickTool(context, (argv, files) => runMogrifyCli(argv, files));
4970
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
4971
+ return executeVfsMagickTool(context2, runMogrifyCli);
4972
+ });
4592
4973
  }
4593
4974
  });
4594
4975
  }
4595
4976
  var mogrifyCommand = createMogrifyCommand();
4596
- function createCompositeCommand(_options = {}) {
4977
+ function createCompositeCommand(options = {}) {
4978
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4597
4979
  return Object.freeze({
4598
4980
  name: "composite",
4599
4981
  runtimeIdentity: commandRuntimeIdentity,
4600
4982
  description: "ImageMagick overlay composition tool powered by @poe-code/image-ast",
4601
4983
  execute(context) {
4602
- return executeVfsMagickTool(context, runCompositeCli);
4984
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
4985
+ return executeVfsMagickTool(context2, runCompositeCli);
4986
+ });
4603
4987
  }
4604
4988
  });
4605
4989
  }
4606
4990
  var compositeCommand = createCompositeCommand();
4607
- function createMontageCommand(_options = {}) {
4991
+ function createMontageCommand(options = {}) {
4992
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4608
4993
  return Object.freeze({
4609
4994
  name: "montage",
4610
4995
  runtimeIdentity: commandRuntimeIdentity,
4611
4996
  description: "ImageMagick contact-sheet grid generator powered by @poe-code/image-ast",
4612
4997
  execute(context) {
4613
- return executeVfsMagickTool(context, runMontageCli);
4998
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
4999
+ return executeVfsMagickTool(context2, runMontageCli);
5000
+ });
4614
5001
  }
4615
5002
  });
4616
5003
  }
4617
5004
  var montageCommand = createMontageCommand();
4618
- function createIdentifyCommand(_options = {}) {
5005
+ function createIdentifyCommand(options = {}) {
5006
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4619
5007
  return Object.freeze({
4620
5008
  name: "identify",
4621
5009
  runtimeIdentity: commandRuntimeIdentity,
4622
5010
  description: "ImageMagick image metadata inspector powered by @poe-code/image-ast",
4623
5011
  execute(context) {
4624
- return executeVfsMagickTool(context, runIdentifyCli);
5012
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
5013
+ return executeVfsMagickTool(context2, runIdentifyCli);
5014
+ });
4625
5015
  }
4626
5016
  });
4627
5017
  }
4628
5018
  var identifyCommand = createIdentifyCommand();
4629
- function createCompareCommand(_options = {}) {
5019
+ function createCompareCommand(options = {}) {
5020
+ const maxInputBytes = InputByteBudget.limit(options.limits?.maxInputBytes);
4630
5021
  return Object.freeze({
4631
5022
  name: "compare",
4632
5023
  runtimeIdentity: commandRuntimeIdentity,
4633
5024
  description: "ImageMagick image comparison and diff generator powered by @poe-code/image-ast",
4634
5025
  execute(context) {
4635
- return executeVfsMagickTool(context, runCompareCli);
5026
+ return new InputByteBudget(maxInputBytes).run(context, async (context2) => {
5027
+ return executeVfsMagickTool(context2, runCompareCli);
5028
+ });
4636
5029
  }
4637
5030
  });
4638
5031
  }
@@ -4663,6 +5056,11 @@ var imagemagickCommands = imagemagickPlugin;
4663
5056
  function createImagemagickCommands(options = {}) {
4664
5057
  return [createMagickCommand(options), createConvertCommand(options), createMogrifyCommand(options), createCompositeCommand(options), createMontageCommand(options), createIdentifyCommand(options), createCompareCommand(options)];
4665
5058
  }
5059
+ function* mapSteps(values, mapper) {
5060
+ const result = [];
5061
+ for (const value of values) result.push(yield* mapper(value));
5062
+ return result;
5063
+ }
4666
5064
  export {
4667
5065
  compareCommand,
4668
5066
  compositeCommand,