@field/cascade 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +25 -5
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +382 -0
- package/README.md +1 -2
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-DSZBpzdy.js → CodeEditor-C-xYG-Wn.js} +120 -120
- package/dist/assets/CodePanel-CtXd50m6.js +2 -0
- package/dist/assets/CookInfoPanel-B3NMhKJF.css +1 -0
- package/dist/assets/CookInfoPanel-DG4_TRsX.js +2 -0
- package/dist/assets/CustomNodeDialog-CHfZUs-r.js +1 -0
- package/dist/assets/DefinitionNode-CaRTXQ_b.js +1 -0
- package/dist/assets/DefinitionPanel-C3CxZY9r.js +1 -0
- package/dist/assets/DefinitionPanel-VNLnAiQD.css +1 -0
- package/dist/assets/OpenGraphDialog-BLdr6k_q.js +1 -0
- package/dist/assets/ProjectSettings-ZnvmIAir.js +2 -0
- package/dist/assets/{SettingsDialog-p25h3tj0.js → SettingsDialog-CBX3Wa87.js} +1 -1
- package/dist/assets/TimelinePanel-CDeR0arY.css +1 -0
- package/dist/assets/TimelinePanel-CWgnFH1e.js +1 -0
- package/dist/assets/{VersionHistoryDialog-DzFLUotB.js → VersionHistoryDialog-BOSoW1R-.js} +1 -1
- package/dist/assets/assert-BO2_erPD.js +1 -0
- package/dist/assets/assert-hvykGCnP.js +1 -0
- package/dist/assets/builder-BmBKcDix.js +1 -0
- package/dist/assets/camera-DFF7YA3F.js +1 -0
- package/dist/assets/checks-DAvyO9Gf.js +1 -0
- package/dist/assets/contactSheet-N1NcaWxw.js +2 -0
- package/dist/assets/{core-BICrEt0y.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-D7TXw57I.js → cssMode-DPVckSOc.js} +1 -1
- package/dist/assets/definitions-B227e7f_.js +1 -0
- package/dist/assets/definitions-D0WOUJd7.js +1 -0
- package/dist/assets/{editor.api-DvkCO3ko.js → editor.api-Dkutg_Z1.js} +1 -1
- package/dist/assets/expressions-X-Z-GrgW.js +5 -0
- package/dist/assets/file-DAL6IfjV.js +1 -0
- package/dist/assets/filters-D3k1LRMa.js +1 -0
- package/dist/assets/{freemarker2-BA2lxsF1.js → freemarker2-CLiLKk3B.js} +1 -1
- package/dist/assets/generators-BhDxRAFC.js +1 -0
- package/dist/assets/geo-BsMImJIJ.js +1 -0
- package/dist/assets/geo-C4YngDob.js +2 -0
- package/dist/assets/{handlebars-BcDiyPd8.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-C7O4TyhX.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-WaDGF3Mj.js → htmlMode-DUD3VaoN.js} +1 -1
- package/dist/assets/image-0SfH-snh.js +1 -0
- package/dist/assets/image-Ck-RdGU4.js +2 -0
- package/dist/assets/index-BWnrmIB9.js +137 -0
- package/dist/assets/index-DIaxEONI.css +1 -0
- package/dist/assets/io-BGmt2g0D.js +1 -0
- package/dist/assets/{javascript-CpIEK7tz.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-B2FltW0f.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-CN6FFHZE.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-QhV9XtLp.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-DE89pafV.js → mdx-BV3jbrVa.js} +1 -1
- package/dist/assets/pop-KMF_qloi.js +1 -0
- package/dist/assets/preload-helper-Czpn1I53.js +1 -0
- package/dist/assets/{python-ByTllTB9.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-USYlRRCE.js → razor-CQfzX3-N.js} +1 -1
- package/dist/assets/remap-5SjXQU-q.js +1 -0
- package/dist/assets/renderMarkdown-ork0Oir7.js +67 -0
- package/dist/assets/studioImages-CAyH-0Pl.js +1 -0
- package/dist/assets/text-ZpX7qNkx.js +2 -0
- package/dist/assets/time-P_OiBhcf.js +1 -0
- package/dist/assets/{tsMode-BXpN8iUz.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-DInBjGQQ.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-C7Ye5B7D.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-U0Uocqyo.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-CBw_PVYf.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/Graph-OB6EWSGL.js +2975 -0
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/chunk-2JEU3MGB.js +1125 -0
- package/dist/cli/chunk-2KXB47FP.js +115 -0
- package/dist/cli/chunk-3RXL5GHB.js +816 -0
- package/dist/cli/chunk-53LGFPWX.js +138 -0
- package/dist/cli/chunk-5ORUQ6ES.js +267 -0
- package/dist/cli/chunk-73S4JZXK.js +336 -0
- package/dist/cli/chunk-7QE2ZNSN.js +121 -0
- package/dist/cli/chunk-BP7UKF36.js +376 -0
- package/dist/cli/chunk-BPODRH52.js +201 -0
- package/dist/cli/chunk-BZ63XQ3I.js +1301 -0
- package/dist/cli/chunk-CKS2FQWR.js +89 -0
- package/dist/cli/chunk-CO22XHNG.js +593 -0
- package/dist/cli/chunk-CTPLRSWF.js +2197 -0
- package/dist/cli/chunk-DEQSEFFH.js +153 -0
- package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
- package/dist/cli/chunk-EZRWJ4G2.js +104 -0
- package/dist/cli/chunk-FWMSGKEH.js +71 -0
- package/dist/cli/chunk-G23A2BZZ.js +705 -0
- package/dist/cli/chunk-GRIN2DDP.js +1465 -0
- package/dist/cli/chunk-HFHWYL55.js +139 -0
- package/dist/cli/chunk-HSNOBIVT.js +263 -0
- package/dist/cli/chunk-ICH7N5PN.js +26 -0
- package/dist/cli/chunk-J7VK7MNF.js +418 -0
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/chunk-KH4MUBKF.js +1551 -0
- package/dist/cli/chunk-L6B6FUQP.js +330 -0
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/chunk-MP653A5O.js +3766 -0
- package/dist/cli/chunk-NJFMDXHR.js +320 -0
- package/dist/cli/chunk-OM6BEME6.js +267 -0
- package/dist/cli/chunk-OWWBYLHC.js +136 -0
- package/dist/cli/chunk-QQPA2ZHH.js +273 -0
- package/dist/cli/chunk-RUU3YWXU.js +99 -0
- package/dist/cli/chunk-RXDIMXN5.js +98 -0
- package/dist/cli/chunk-ST6LROUG.js +267 -0
- package/dist/cli/chunk-TJW67QSI.js +225 -0
- package/dist/cli/chunk-WD62JIP6.js +118 -0
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/chunk-X4WKAOQP.js +634 -0
- package/dist/cli/chunk-X566FWBV.js +156 -0
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/cliCommands-JJN5Z3ZC.js +3470 -0
- package/dist/cli/commands-PHYFYA3F.js +1374 -0
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/definitions-BPOPW52L.js +32 -0
- package/dist/cli/doctorCommand-ORWQRNYP.js +106 -0
- package/dist/cli/edit-S5KEQ5RA.js +28 -0
- package/dist/cli/editorCommands-NFR32JOY.js +41 -0
- package/dist/cli/encode-ICPEPMH5.js +17 -0
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/frames-LSAUBZ7P.js +16 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/geo-6ZPGKZRU.js +43 -0
- package/dist/cli/graphCommands-EOUOBOIJ.js +184 -0
- package/dist/cli/graphFile-YTGJB5F5.js +292 -0
- package/dist/cli/headlessCanvas-ENRHC7GS.js +16 -0
- package/dist/cli/helpCommand-PULH6ZYB.js +157 -0
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +100 -30756
- package/dist/cli/math-RSYRQ3C6.js +16 -0
- package/dist/cli/mcp-JVZFQOEX.js +164 -0
- package/dist/cli/parity-X6DEH2DV.js +334 -0
- package/dist/cli/pop-B7SIIYKN.js +39 -0
- package/dist/cli/project-VYGIA7JX.js +12 -0
- package/dist/cli/projectDefinition-F3D7UIHJ.js +27 -0
- package/dist/cli/projectRuntime-2Q4JKEH3.js +55 -0
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/render-PT4MWI6U.js +438 -0
- package/dist/cli/runCommand-HNPQVZMS.js +198 -0
- package/dist/cli/runner-5XPXVW7J.js +43 -0
- package/dist/cli/runtime/image.ts +302 -0
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/runtime/stage.ts +4 -1
- package/dist/cli/share-MHF6TNRK.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/stageRunner-KY2EJP7X.js +10 -0
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/verbs-PI2JH5FI.js +19 -0
- package/dist/cli/webBuild-WPPMGGW7.js +44 -0
- package/dist/contracts/capabilities.d.ts +18 -1
- package/dist/contracts/color.d.ts +8 -0
- package/dist/contracts/color.js +23 -0
- package/dist/contracts/definition.d.ts +10 -0
- package/dist/contracts/documentFormat.d.ts +18 -0
- package/dist/contracts/documentFormat.js +195 -0
- package/dist/contracts/editor.d.ts +17 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/schema.d.ts +1 -1
- package/dist/contracts/schema.js +1 -0
- package/dist/contracts/validate.js +11 -1
- package/dist/contracts/values.d.ts +24 -0
- package/dist/image.d.ts +156 -0
- package/dist/image.js +161 -0
- package/dist/index.html +8 -2
- package/dist/io.d.ts +29 -0
- package/dist/io.js +40 -0
- package/dist/player/app.js +3 -2
- package/dist/player/editor.js +35 -9
- package/dist/player/editorEngine.js +3 -2
- package/dist/runtime/builtins/assert/checks.d.ts +18 -0
- package/dist/runtime/builtins/assert/checks.js +207 -0
- package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
- package/dist/runtime/builtins/assert/definitions.js +54 -0
- package/dist/runtime/builtins/assert/index.d.ts +152 -0
- package/dist/runtime/builtins/assert/index.js +36 -0
- package/dist/runtime/builtins/image/contactSheet.d.ts +64 -0
- package/dist/runtime/builtins/image/contactSheet.js +150 -0
- package/dist/runtime/builtins/image/definitions.d.ts +950 -0
- package/dist/runtime/builtins/image/definitions.js +343 -0
- package/dist/runtime/builtins/image/file.d.ts +8 -0
- package/dist/runtime/builtins/image/file.js +37 -0
- package/dist/runtime/builtins/image/filters.d.ts +8 -0
- package/dist/runtime/builtins/image/filters.js +394 -0
- package/dist/runtime/builtins/image/generators.d.ts +7 -0
- package/dist/runtime/builtins/image/generators.js +144 -0
- package/dist/runtime/builtins/image/index.d.ts +952 -0
- package/dist/runtime/builtins/image/index.js +44 -0
- package/dist/runtime/builtins/image/io.d.ts +100 -0
- package/dist/runtime/builtins/image/io.js +142 -0
- package/dist/runtime/builtins/image/planar.d.ts +55 -0
- package/dist/runtime/builtins/image/planar.js +274 -0
- package/dist/runtime/builtins/image/simplex.d.ts +22 -0
- package/dist/runtime/builtins/image/simplex.js +92 -0
- package/dist/runtime/builtins/image/text.d.ts +4 -0
- package/dist/runtime/builtins/image/text.js +141 -0
- package/dist/runtime/builtins/index.d.ts +3 -0
- package/dist/runtime/builtins/index.js +7 -0
- package/dist/runtime/gpu.d.ts +25 -0
- package/dist/runtime/gpu.js +40 -0
- package/dist/runtime/runtime.d.ts +2 -0
- package/dist/runtime/runtime.js +268 -44
- package/dist/runtime/types.d.ts +30 -0
- package/dist/stage.js +4 -1
- package/doc/CLI_REFERENCE.md +91 -2
- package/doc/EDITOR_EXPORT.md +37 -2
- package/doc/MCP.md +18 -1
- package/doc/NODE_REFERENCE.md +424 -10
- package/doc/PROJECT_AUTHORING.md +222 -7
- package/package.json +19 -4
- package/dist/assets/CodePanel-sY6sZa7B.js +0 -2
- package/dist/assets/CustomNodeDialog-BRKnqZhp.js +0 -1
- package/dist/assets/ExportDialog-C7dVGua4.js +0 -358
- package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
- package/dist/assets/OpenGraphDialog-ZsgL-iwr.js +0 -1
- package/dist/assets/ProjectSettings-Cw17nNe3.js +0 -2
- package/dist/assets/definitions-DUww2Rt-.js +0 -1
- package/dist/assets/geo-C2RHOVHC.js +0 -1
- package/dist/assets/image-DR4oeyJB.js +0 -2062
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/index-DyvDC6pS.js +0 -219
- package/dist/assets/math-DaDEgWKt.js +0 -1
- package/dist/assets/pop-pLH7L0PW.js +0 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
// packages/runtime/src/builtins/image/planar.ts
|
|
2
|
+
var Planar = class _Planar {
|
|
3
|
+
constructor(width, height, channels) {
|
|
4
|
+
pixelCount(width, height);
|
|
5
|
+
this.width = width;
|
|
6
|
+
this.height = height;
|
|
7
|
+
this.channels = channels;
|
|
8
|
+
}
|
|
9
|
+
static grayscale(width, height) {
|
|
10
|
+
return new _Planar(width, height, [new Float32Array(pixelCount(width, height))]);
|
|
11
|
+
}
|
|
12
|
+
static rgba(width, height) {
|
|
13
|
+
const size = pixelCount(width, height);
|
|
14
|
+
return new _Planar(width, height, [
|
|
15
|
+
new Float32Array(size),
|
|
16
|
+
new Float32Array(size),
|
|
17
|
+
new Float32Array(size),
|
|
18
|
+
new Float32Array(size)
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
/** From 8-bit RGBA, unpremultiplied. */
|
|
22
|
+
static fromPixels(pixels) {
|
|
23
|
+
const { width, height, data } = pixels;
|
|
24
|
+
const size = width * height;
|
|
25
|
+
const r = new Float32Array(size);
|
|
26
|
+
const g = new Float32Array(size);
|
|
27
|
+
const b = new Float32Array(size);
|
|
28
|
+
const a = new Float32Array(size);
|
|
29
|
+
const inv255 = 1 / 255;
|
|
30
|
+
for (let i = 0; i < size; i++) {
|
|
31
|
+
const idx = i * 4;
|
|
32
|
+
r[i] = data[idx] * inv255;
|
|
33
|
+
g[i] = data[idx + 1] * inv255;
|
|
34
|
+
b[i] = data[idx + 2] * inv255;
|
|
35
|
+
a[i] = data[idx + 3] * inv255;
|
|
36
|
+
}
|
|
37
|
+
return new _Planar(width, height, [r, g, b, a]);
|
|
38
|
+
}
|
|
39
|
+
static solid(width, height, color) {
|
|
40
|
+
const buffer = _Planar.rgba(width, height);
|
|
41
|
+
buffer.fill(0, color.r);
|
|
42
|
+
buffer.fill(1, color.g);
|
|
43
|
+
buffer.fill(2, color.b);
|
|
44
|
+
buffer.fill(3, color.a ?? 1);
|
|
45
|
+
return buffer;
|
|
46
|
+
}
|
|
47
|
+
get channelCount() {
|
|
48
|
+
return this.channels.length;
|
|
49
|
+
}
|
|
50
|
+
get pixelCount() {
|
|
51
|
+
return this.width * this.height;
|
|
52
|
+
}
|
|
53
|
+
fill(channel, value) {
|
|
54
|
+
this.channels[channel].fill(value);
|
|
55
|
+
}
|
|
56
|
+
clone() {
|
|
57
|
+
return new _Planar(this.width, this.height, this.channels.map((channel) => new Float32Array(channel)));
|
|
58
|
+
}
|
|
59
|
+
emptyClone() {
|
|
60
|
+
return new _Planar(this.width, this.height, this.channels.map(() => new Float32Array(this.pixelCount)));
|
|
61
|
+
}
|
|
62
|
+
toRGBA() {
|
|
63
|
+
if (this.channels.length >= 4) return this.clone();
|
|
64
|
+
const result = _Planar.rgba(this.width, this.height);
|
|
65
|
+
const [r, g = r, b = r] = this.channels.length === 1 ? [this.channels[0]] : this.channels;
|
|
66
|
+
result.channels[0].set(r);
|
|
67
|
+
result.channels[1].set(g);
|
|
68
|
+
result.channels[2].set(b);
|
|
69
|
+
result.channels[3].fill(1);
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
/** To 8-bit RGBA: a grey image fills red, green and blue, and no alpha is opaque. */
|
|
73
|
+
toPixels() {
|
|
74
|
+
const size = this.pixelCount;
|
|
75
|
+
const data = new Uint8ClampedArray(size * 4);
|
|
76
|
+
const r = this.channels[0];
|
|
77
|
+
const g = this.channels.length > 1 ? this.channels[1] : r;
|
|
78
|
+
const b = this.channels.length > 2 ? this.channels[2] : r;
|
|
79
|
+
const a = this.channels.length > 3 ? this.channels[3] : null;
|
|
80
|
+
for (let i = 0; i < size; i++) {
|
|
81
|
+
const idx = i << 2;
|
|
82
|
+
let v = r[i] * 255 + 0.5 | 0;
|
|
83
|
+
data[idx] = v < 0 ? 0 : v > 255 ? 255 : v;
|
|
84
|
+
v = g[i] * 255 + 0.5 | 0;
|
|
85
|
+
data[idx + 1] = v < 0 ? 0 : v > 255 ? 255 : v;
|
|
86
|
+
v = b[i] * 255 + 0.5 | 0;
|
|
87
|
+
data[idx + 2] = v < 0 ? 0 : v > 255 ? 255 : v;
|
|
88
|
+
if (a) {
|
|
89
|
+
v = a[i] * 255 + 0.5 | 0;
|
|
90
|
+
data[idx + 3] = v < 0 ? 0 : v > 255 ? 255 : v;
|
|
91
|
+
} else {
|
|
92
|
+
data[idx + 3] = 255;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { width: this.width, height: this.height, data };
|
|
96
|
+
}
|
|
97
|
+
/** Bilinear, clamped at the edges (or wrapped). */
|
|
98
|
+
sample(x, y, channel = 0, wrap = false) {
|
|
99
|
+
const x0 = Math.floor(x);
|
|
100
|
+
const y0 = Math.floor(y);
|
|
101
|
+
const fx = x - x0;
|
|
102
|
+
const fy = y - y0;
|
|
103
|
+
const ch = this.channels[channel];
|
|
104
|
+
const w = this.width;
|
|
105
|
+
const h = this.height;
|
|
106
|
+
const px0 = edge(x0, w, wrap);
|
|
107
|
+
const px1 = edge(x0 + 1, w, wrap);
|
|
108
|
+
const py0 = edge(y0, h, wrap);
|
|
109
|
+
const py1 = edge(y0 + 1, h, wrap);
|
|
110
|
+
const v0 = ch[py0 * w + px0] * (1 - fx) + ch[py0 * w + px1] * fx;
|
|
111
|
+
const v1 = ch[py1 * w + px0] * (1 - fx) + ch[py1 * w + px1] * fx;
|
|
112
|
+
return v0 * (1 - fy) + v1 * fy;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
function edge(coord, max, wrap) {
|
|
116
|
+
return wrap ? (coord % max + max) % max : Math.max(0, Math.min(max - 1, coord));
|
|
117
|
+
}
|
|
118
|
+
function pixelCount(width, height) {
|
|
119
|
+
const count = width * height;
|
|
120
|
+
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width < 1 || height < 1 || !Number.isSafeInteger(count)) {
|
|
121
|
+
throw new RangeError(`Image dimensions must be positive safe integers; received ${width}\xD7${height}`);
|
|
122
|
+
}
|
|
123
|
+
return count;
|
|
124
|
+
}
|
|
125
|
+
function resample(source, width, height) {
|
|
126
|
+
const result = Planar.rgba(width, height);
|
|
127
|
+
const scaleX = source.width / width;
|
|
128
|
+
const scaleY = source.height / height;
|
|
129
|
+
for (let c = 0; c < Math.min(source.channelCount, 4); c++) {
|
|
130
|
+
const dst = result.channels[c];
|
|
131
|
+
for (let y = 0; y < height; y++) {
|
|
132
|
+
for (let x = 0; x < width; x++) {
|
|
133
|
+
dst[y * width + x] = source.sample(x * scaleX, y * scaleY, c);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (source.channelCount < 4) result.fill(3, 1);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
function resolveOutputSize(mode, inputs, customSize) {
|
|
141
|
+
const valid = inputs.filter((buffer) => buffer !== null);
|
|
142
|
+
const area = (buffer) => buffer.width * buffer.height;
|
|
143
|
+
switch (mode) {
|
|
144
|
+
case "input":
|
|
145
|
+
case "input1":
|
|
146
|
+
if (valid[0]) return { width: valid[0].width, height: valid[0].height };
|
|
147
|
+
break;
|
|
148
|
+
case "input2": {
|
|
149
|
+
const chosen = valid[1] ?? valid[0];
|
|
150
|
+
if (chosen) return { width: chosen.width, height: chosen.height };
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case "largest":
|
|
154
|
+
case "smallest":
|
|
155
|
+
if (valid.length > 0) {
|
|
156
|
+
let best = valid[0];
|
|
157
|
+
let bestArea = mode === "largest" ? 0 : Infinity;
|
|
158
|
+
for (const buffer of valid) {
|
|
159
|
+
if (mode === "largest" ? area(buffer) > bestArea : area(buffer) < bestArea) {
|
|
160
|
+
bestArea = area(buffer);
|
|
161
|
+
best = buffer;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { width: best.width, height: best.height };
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case "custom":
|
|
168
|
+
if (customSize) return { width: customSize[0], height: customSize[1] };
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
if (valid[0]) return { width: valid[0].width, height: valid[0].height };
|
|
172
|
+
return { width: 512, height: 512 };
|
|
173
|
+
}
|
|
174
|
+
function resizeToFit(source, targetWidth, targetHeight, fitMode = "fill") {
|
|
175
|
+
if (source.width === targetWidth && source.height === targetHeight) return source;
|
|
176
|
+
const result = Planar.rgba(targetWidth, targetHeight);
|
|
177
|
+
const srcAspect = source.width / source.height;
|
|
178
|
+
const dstAspect = targetWidth / targetHeight;
|
|
179
|
+
let srcX = 0, srcY = 0, srcW = source.width, srcH = source.height;
|
|
180
|
+
let dstX = 0, dstY = 0, dstW = targetWidth, dstH = targetHeight;
|
|
181
|
+
const black = () => {
|
|
182
|
+
result.fill(0, 0);
|
|
183
|
+
result.fill(1, 0);
|
|
184
|
+
result.fill(2, 0);
|
|
185
|
+
result.fill(3, 1);
|
|
186
|
+
};
|
|
187
|
+
switch (fitMode) {
|
|
188
|
+
case "fill":
|
|
189
|
+
if (srcAspect > dstAspect) {
|
|
190
|
+
srcW = Math.round(source.height * dstAspect);
|
|
191
|
+
srcX = Math.round((source.width - srcW) / 2);
|
|
192
|
+
} else {
|
|
193
|
+
srcH = Math.round(source.width / dstAspect);
|
|
194
|
+
srcY = Math.round((source.height - srcH) / 2);
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
case "fit":
|
|
198
|
+
if (srcAspect > dstAspect) {
|
|
199
|
+
dstH = Math.round(targetWidth / srcAspect);
|
|
200
|
+
dstY = Math.round((targetHeight - dstH) / 2);
|
|
201
|
+
} else {
|
|
202
|
+
dstW = Math.round(targetHeight * srcAspect);
|
|
203
|
+
dstX = Math.round((targetWidth - dstW) / 2);
|
|
204
|
+
}
|
|
205
|
+
black();
|
|
206
|
+
break;
|
|
207
|
+
case "stretch":
|
|
208
|
+
break;
|
|
209
|
+
case "native":
|
|
210
|
+
dstW = Math.min(source.width, targetWidth);
|
|
211
|
+
dstH = Math.min(source.height, targetHeight);
|
|
212
|
+
srcW = dstW;
|
|
213
|
+
srcH = dstH;
|
|
214
|
+
dstX = Math.round((targetWidth - dstW) / 2);
|
|
215
|
+
dstY = Math.round((targetHeight - dstH) / 2);
|
|
216
|
+
srcX = Math.round((source.width - srcW) / 2);
|
|
217
|
+
srcY = Math.round((source.height - srcH) / 2);
|
|
218
|
+
black();
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
const scaleX = srcW / dstW;
|
|
222
|
+
const scaleY = srcH / dstH;
|
|
223
|
+
for (let c = 0; c < Math.min(source.channelCount, 4); c++) {
|
|
224
|
+
const dst = result.channels[c];
|
|
225
|
+
for (let y = 0; y < dstH; y++) {
|
|
226
|
+
for (let x = 0; x < dstW; x++) {
|
|
227
|
+
dst[(dstY + y) * targetWidth + (dstX + x)] = source.sample(srcX + x * scaleX, srcY + y * scaleY, c);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (source.channelCount < 4 && fitMode !== "fit" && fitMode !== "native") {
|
|
232
|
+
const alpha = result.channels[3];
|
|
233
|
+
for (let y = 0; y < dstH; y++) {
|
|
234
|
+
for (let x = 0; x < dstW; x++) alpha[(dstY + y) * targetWidth + (dstX + x)] = 1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// packages/runtime/src/builtins/image/io.ts
|
|
241
|
+
var NO_CANVAS = 'cascade.image: this host has no canvas. In a browser this needs OffscreenCanvas; headless, Cascade installs @napi-rs/canvas before a run (install it with "npm install @napi-rs/canvas" if it is missing).';
|
|
242
|
+
function canvasGlobals() {
|
|
243
|
+
return globalThis;
|
|
244
|
+
}
|
|
245
|
+
function surface(width, height) {
|
|
246
|
+
const Canvas = canvasGlobals().OffscreenCanvas;
|
|
247
|
+
if (!Canvas) throw new Error(NO_CANVAS);
|
|
248
|
+
const canvas = new Canvas(width, height);
|
|
249
|
+
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
250
|
+
if (!context) throw new Error("cascade.image: the canvas has no 2D context");
|
|
251
|
+
return { canvas, context };
|
|
252
|
+
}
|
|
253
|
+
function assetsOf(context) {
|
|
254
|
+
const assets = context.capabilities.assets;
|
|
255
|
+
if (!assets) throw new Error(`${context.nodeId}: this host gives cascade.image nodes no assets capability`);
|
|
256
|
+
return assets;
|
|
257
|
+
}
|
|
258
|
+
function imageReference(value) {
|
|
259
|
+
if (typeof value === "string") return value ? { path: value } : null;
|
|
260
|
+
const path = value?.path;
|
|
261
|
+
return typeof path === "string" && path ? { path } : null;
|
|
262
|
+
}
|
|
263
|
+
async function decodePixels(bytes) {
|
|
264
|
+
const globals = canvasGlobals();
|
|
265
|
+
if (!globals.createImageBitmap || !globals.Blob) throw new Error(NO_CANVAS);
|
|
266
|
+
const bitmap = await globals.createImageBitmap(new globals.Blob([bytes]));
|
|
267
|
+
try {
|
|
268
|
+
const { width, height } = bitmap;
|
|
269
|
+
if (!width || !height) throw new Error("cascade.image: could not decode the image data");
|
|
270
|
+
const { context } = surface(width, height);
|
|
271
|
+
context.drawImage(bitmap, 0, 0);
|
|
272
|
+
return { width, height, data: context.getImageData(0, 0, width, height).data };
|
|
273
|
+
} finally {
|
|
274
|
+
bitmap.close?.();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function readPixelsFromCanvas(canvas) {
|
|
278
|
+
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
279
|
+
if (!context) throw new Error("cascade.image: the canvas has no 2D context");
|
|
280
|
+
return { width: canvas.width, height: canvas.height, data: context.getImageData(0, 0, canvas.width, canvas.height).data };
|
|
281
|
+
}
|
|
282
|
+
async function readPixels(context, ref) {
|
|
283
|
+
const assets = assetsOf(context);
|
|
284
|
+
const kept = assets.imagePixels?.(ref);
|
|
285
|
+
if (kept) return kept;
|
|
286
|
+
return decodePixels(await assets.read(ref, { signal: context.signal }));
|
|
287
|
+
}
|
|
288
|
+
async function readPlanar(context, value) {
|
|
289
|
+
const ref = imageReference(value);
|
|
290
|
+
return ref ? Planar.fromPixels(await readPixels(context, ref)) : null;
|
|
291
|
+
}
|
|
292
|
+
async function encodePng(pixels) {
|
|
293
|
+
const globals = canvasGlobals();
|
|
294
|
+
if (!globals.ImageData) throw new Error(NO_CANVAS);
|
|
295
|
+
const { canvas, context } = surface(pixels.width, pixels.height);
|
|
296
|
+
context.putImageData(new globals.ImageData(pixels.data, pixels.width, pixels.height), 0, 0);
|
|
297
|
+
const blob = await canvas.convertToBlob({ type: "image/png" });
|
|
298
|
+
return new Uint8Array(await blob.arrayBuffer());
|
|
299
|
+
}
|
|
300
|
+
async function writePixels(context, pixels) {
|
|
301
|
+
const assets = assetsOf(context);
|
|
302
|
+
const name = `${context.nodeId}.png`;
|
|
303
|
+
const options = { signal: context.signal };
|
|
304
|
+
const stored = assets.keepImage ? await assets.keepImage(pixels, { suggestedName: name }, options) : await assets.write(await encodePng(pixels), { mediaType: "image/png", suggestedName: name }, options);
|
|
305
|
+
return { path: stored.path, size: [pixels.width, pixels.height], channels: "rgba", depth: "u8", space: "srgb" };
|
|
306
|
+
}
|
|
307
|
+
async function output(context, image) {
|
|
308
|
+
context.outputs.image.set(await writePixels(context, image.toPixels()));
|
|
309
|
+
}
|
|
310
|
+
function normalizeColor(input) {
|
|
311
|
+
if (input && typeof input === "object" && !Array.isArray(input) && "r" in input && "g" in input && "b" in input) {
|
|
312
|
+
const color = input;
|
|
313
|
+
const unit = color.r <= 1 && color.g <= 1 && color.b <= 1;
|
|
314
|
+
return {
|
|
315
|
+
r: unit ? color.r : color.r / 255,
|
|
316
|
+
g: unit ? color.g : color.g / 255,
|
|
317
|
+
b: unit ? color.b : color.b / 255,
|
|
318
|
+
a: color.a !== void 0 ? unit ? color.a : color.a / 255 : 1
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if (Array.isArray(input)) {
|
|
322
|
+
const unit = input.every((value) => value <= 1);
|
|
323
|
+
return {
|
|
324
|
+
r: unit ? input[0] : input[0] / 255,
|
|
325
|
+
g: unit ? input[1] : input[1] / 255,
|
|
326
|
+
b: unit ? input[2] : input[2] / 255,
|
|
327
|
+
a: input[3] !== void 0 ? unit ? input[3] : input[3] / 255 : 1
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (typeof input === "string") {
|
|
331
|
+
const rgb = input.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);
|
|
332
|
+
if (rgb) return { r: parseInt(rgb[1], 10) / 255, g: parseInt(rgb[2], 10) / 255, b: parseInt(rgb[3], 10) / 255, a: 1 };
|
|
333
|
+
const hex = input.replace("#", "");
|
|
334
|
+
if (hex.length === 3 || hex.length === 6) {
|
|
335
|
+
const expanded = hex.length === 3 ? hex.split("").map((digit) => digit + digit).join("") : hex;
|
|
336
|
+
const parts = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(expanded);
|
|
337
|
+
if (parts) return { r: parseInt(parts[1], 16) / 255, g: parseInt(parts[2], 16) / 255, b: parseInt(parts[3], 16) / 255, a: 1 };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return { r: 0, g: 0, b: 0, a: 1 };
|
|
341
|
+
}
|
|
342
|
+
function colorToCss(color) {
|
|
343
|
+
const r = Math.round(color.r * 255);
|
|
344
|
+
const g = Math.round(color.g * 255);
|
|
345
|
+
const b = Math.round(color.b * 255);
|
|
346
|
+
const a = color.a !== void 0 ? color.a : 1;
|
|
347
|
+
return a < 1 ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export {
|
|
351
|
+
Planar,
|
|
352
|
+
resample,
|
|
353
|
+
resolveOutputSize,
|
|
354
|
+
resizeToFit,
|
|
355
|
+
surface,
|
|
356
|
+
imageReference,
|
|
357
|
+
readPixelsFromCanvas,
|
|
358
|
+
readPlanar,
|
|
359
|
+
writePixels,
|
|
360
|
+
output,
|
|
361
|
+
normalizeColor,
|
|
362
|
+
colorToCss
|
|
363
|
+
};
|
|
364
|
+
//# sourceMappingURL=chunk-WGKPJZDY.js.map
|