@workglow/util 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +81 -16
- package/dist/browser.js.map +4 -4
- package/dist/bun.js +81 -16
- package/dist/bun.js.map +4 -4
- package/dist/json-schema/SchemaUtils.d.ts.map +1 -1
- package/dist/json-schema/SchemaValidation.d.ts +6 -0
- package/dist/json-schema/SchemaValidation.d.ts.map +1 -1
- package/dist/media/cpuImage.d.ts +15 -16
- package/dist/media/cpuImage.d.ts.map +1 -1
- package/dist/media/encode.d.ts +3 -5
- package/dist/media/encode.d.ts.map +1 -1
- package/dist/media/gpuImage.d.ts +21 -30
- package/dist/media/gpuImage.d.ts.map +1 -1
- package/dist/media/imageCacheCodec.d.ts +19 -7
- package/dist/media/imageCacheCodec.d.ts.map +1 -1
- package/dist/media/imageRasterCodecRegistry.d.ts +3 -3
- package/dist/media/imageRasterCodecRegistry.d.ts.map +1 -1
- package/dist/media/imageTypes.d.ts +0 -16
- package/dist/media/imageTypes.d.ts.map +1 -1
- package/dist/media/imageValue.d.ts +44 -0
- package/dist/media/imageValue.d.ts.map +1 -0
- package/dist/media/imageValue.test.d.ts +7 -0
- package/dist/media/imageValue.test.d.ts.map +1 -0
- package/dist/media/imageValueSchema.d.ts +15 -0
- package/dist/media/imageValueSchema.d.ts.map +1 -0
- package/dist/media/previewBudget.d.ts +10 -13
- package/dist/media/previewBudget.d.ts.map +1 -1
- package/dist/media/rawPixelBuffer.d.ts +20 -0
- package/dist/media/rawPixelBuffer.d.ts.map +1 -0
- package/dist/media/{sharpImage.node.d.ts → sharpImage.server.d.ts} +42 -14
- package/dist/media/sharpImage.server.d.ts.map +1 -0
- package/dist/media/webGpuImage.browser.d.ts +11 -14
- package/dist/media/webGpuImage.browser.d.ts.map +1 -1
- package/dist/media-browser.d.ts +9 -3
- package/dist/media-browser.d.ts.map +1 -1
- package/dist/media-browser.js +429 -342
- package/dist/media-browser.js.map +14 -14
- package/dist/media-node.d.ts +8 -6
- package/dist/media-node.d.ts.map +1 -1
- package/dist/media-node.js +479 -254
- package/dist/media-node.js.map +14 -14
- package/dist/node.js +81 -16
- package/dist/node.js.map +4 -4
- package/dist/schema-entry.js +166 -165
- package/dist/schema-entry.js.map +5 -5
- package/dist/utilities/Misc.d.ts +1 -1
- package/dist/utilities/Misc.d.ts.map +1 -1
- package/dist/worker/WorkerManager.d.ts.map +1 -1
- package/dist/worker-browser.js +5 -2
- package/dist/worker-browser.js.map +3 -3
- package/dist/worker-bun.js +5 -2
- package/dist/worker-bun.js.map +3 -3
- package/dist/worker-node.js +5 -2
- package/dist/worker-node.js.map +3 -3
- package/package.json +1 -1
- package/dist/media/gpuImageSchema.d.ts +0 -8
- package/dist/media/gpuImageSchema.d.ts.map +0 -1
- package/dist/media/sharpImage.bun.d.ts +0 -7
- package/dist/media/sharpImage.bun.d.ts.map +0 -1
- package/dist/media/sharpImage.node.d.ts.map +0 -1
package/dist/media-browser.js
CHANGED
|
@@ -1,39 +1,13 @@
|
|
|
1
1
|
// src/media/imageCacheCodec.ts
|
|
2
2
|
import { registerPortCodec } from "@workglow/util";
|
|
3
3
|
|
|
4
|
-
// src/media/gpuImage.ts
|
|
5
|
-
var GLOBAL_FACTORY_KEY = Symbol.for("@workglow/util/media/gpuImageFactory");
|
|
6
|
-
var _g = globalThis;
|
|
7
|
-
if (!_g[GLOBAL_FACTORY_KEY]) {
|
|
8
|
-
_g[GLOBAL_FACTORY_KEY] = {};
|
|
9
|
-
}
|
|
10
|
-
var factory = _g[GLOBAL_FACTORY_KEY];
|
|
11
|
-
function registerGpuImageFactory(key, fn) {
|
|
12
|
-
factory[key] = fn;
|
|
13
|
-
}
|
|
14
|
-
function getGpuImageFactory(key) {
|
|
15
|
-
const fn = factory[key];
|
|
16
|
-
return typeof fn === "function" ? fn : undefined;
|
|
17
|
-
}
|
|
18
|
-
var GpuImage = new Proxy({}, {
|
|
19
|
-
get(_t, prop) {
|
|
20
|
-
if (typeof prop !== "string" || prop === "then")
|
|
21
|
-
return;
|
|
22
|
-
const fn = factory[prop];
|
|
23
|
-
if (typeof fn !== "function") {
|
|
24
|
-
throw new Error(`GpuImage.${prop} is not registered. Import the platform entry point.`);
|
|
25
|
-
}
|
|
26
|
-
return fn;
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
4
|
// src/media/imageRasterCodecRegistry.ts
|
|
31
5
|
var GLOBAL_CODEC_KEY = Symbol.for("@workglow/util/media/imageRasterCodec");
|
|
32
|
-
var
|
|
33
|
-
if (!
|
|
34
|
-
|
|
6
|
+
var _g = globalThis;
|
|
7
|
+
if (!_g[GLOBAL_CODEC_KEY]) {
|
|
8
|
+
_g[GLOBAL_CODEC_KEY] = { value: null };
|
|
35
9
|
}
|
|
36
|
-
var slot =
|
|
10
|
+
var slot = _g[GLOBAL_CODEC_KEY];
|
|
37
11
|
function registerImageRasterCodec(next) {
|
|
38
12
|
slot.value = next;
|
|
39
13
|
}
|
|
@@ -44,130 +18,170 @@ function getImageRasterCodec() {
|
|
|
44
18
|
return slot.value;
|
|
45
19
|
}
|
|
46
20
|
|
|
47
|
-
// src/media/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
jpeg: "image/jpeg",
|
|
51
|
-
webp: "image/webp"
|
|
52
|
-
};
|
|
53
|
-
function dataUriToBytes(dataUri) {
|
|
54
|
-
const comma = dataUri.indexOf(",");
|
|
55
|
-
const b64 = dataUri.slice(comma + 1);
|
|
56
|
-
const bin = atob(b64);
|
|
57
|
-
const bytes = new Uint8Array(bin.length);
|
|
58
|
-
for (let i = 0;i < bin.length; i++)
|
|
59
|
-
bytes[i] = bin.charCodeAt(i);
|
|
60
|
-
return bytes;
|
|
21
|
+
// src/media/imageValue.ts
|
|
22
|
+
function imageValueFromBitmap(bitmap, width, height, previewScale = 1) {
|
|
23
|
+
return { bitmap, width, height, previewScale };
|
|
61
24
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
return bin.data;
|
|
65
|
-
const px = bin.width * bin.height;
|
|
66
|
-
const out = new Uint8ClampedArray(px * 4);
|
|
67
|
-
if (bin.channels === 3) {
|
|
68
|
-
for (let i = 0;i < px; i++) {
|
|
69
|
-
out[i * 4 + 0] = bin.data[i * 3 + 0] ?? 0;
|
|
70
|
-
out[i * 4 + 1] = bin.data[i * 3 + 1] ?? 0;
|
|
71
|
-
out[i * 4 + 2] = bin.data[i * 3 + 2] ?? 0;
|
|
72
|
-
out[i * 4 + 3] = 255;
|
|
73
|
-
}
|
|
74
|
-
} else if (bin.channels === 1) {
|
|
75
|
-
for (let i = 0;i < px; i++) {
|
|
76
|
-
const g = bin.data[i] ?? 0;
|
|
77
|
-
out[i * 4 + 0] = g;
|
|
78
|
-
out[i * 4 + 1] = g;
|
|
79
|
-
out[i * 4 + 2] = g;
|
|
80
|
-
out[i * 4 + 3] = 255;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return out;
|
|
25
|
+
function imageValueFromBuffer(buffer, format, width, height, previewScale = 1) {
|
|
26
|
+
return { buffer, format, width, height, previewScale };
|
|
84
27
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
28
|
+
function isImageValue(v) {
|
|
29
|
+
return isBrowserImageValue(v) || isNodeImageValue(v);
|
|
30
|
+
}
|
|
31
|
+
function isBrowserImageValue(v) {
|
|
32
|
+
if (v === null || typeof v !== "object")
|
|
33
|
+
return false;
|
|
34
|
+
const o = v;
|
|
35
|
+
return typeof o.width === "number" && typeof o.height === "number" && typeof o.previewScale === "number" && typeof ImageBitmap !== "undefined" && o.bitmap instanceof ImageBitmap;
|
|
36
|
+
}
|
|
37
|
+
function isNodeImageValue(v) {
|
|
38
|
+
if (v === null || typeof v !== "object")
|
|
39
|
+
return false;
|
|
40
|
+
const o = v;
|
|
41
|
+
return typeof o.width === "number" && typeof o.height === "number" && typeof o.previewScale === "number" && typeof Buffer !== "undefined" && Buffer.isBuffer(o.buffer) && (o.format === "png" || o.format === "jpeg" || o.format === "raw-rgba");
|
|
42
|
+
}
|
|
43
|
+
async function normalizeToImageValue(value) {
|
|
44
|
+
if (value === null || value === undefined)
|
|
45
|
+
return;
|
|
46
|
+
if (isImageValue(value))
|
|
47
|
+
return value;
|
|
48
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
49
|
+
if (typeof createImageBitmap === "function") {
|
|
50
|
+
const bitmap = await createImageBitmap(value);
|
|
51
|
+
return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
93
54
|
}
|
|
94
|
-
|
|
95
|
-
return
|
|
55
|
+
if (typeof ImageBitmap !== "undefined" && value instanceof ImageBitmap) {
|
|
56
|
+
return imageValueFromBitmap(value, value.width, value.height);
|
|
96
57
|
}
|
|
97
|
-
|
|
98
|
-
|
|
58
|
+
if (typeof value === "string" && value.startsWith("data:")) {
|
|
59
|
+
if (typeof createImageBitmap === "function" && typeof fetch === "function") {
|
|
60
|
+
const blob = await (await fetch(value)).blob();
|
|
61
|
+
const bitmap = await createImageBitmap(blob);
|
|
62
|
+
return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
|
|
63
|
+
}
|
|
64
|
+
if (typeof Buffer !== "undefined") {
|
|
65
|
+
return decodeDataUriToNodeImageValue(value);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
99
68
|
}
|
|
100
|
-
|
|
101
|
-
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
async function decodeDataUriToNodeImageValue(dataUri) {
|
|
72
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(dataUri);
|
|
73
|
+
if (!match)
|
|
74
|
+
return;
|
|
75
|
+
const mime = match[1] ?? "image/png";
|
|
76
|
+
const base64 = match[2] ?? "";
|
|
77
|
+
const buffer = Buffer.from(base64, "base64");
|
|
78
|
+
const format = /jpe?g/i.test(mime) ? "jpeg" : "png";
|
|
79
|
+
try {
|
|
80
|
+
const decoded = await getImageRasterCodec().decodeDataUri(dataUri);
|
|
81
|
+
return imageValueFromBuffer(buffer, format, decoded.width, decoded.height);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
throw new Error("normalizeToImageValue: failed to probe data URI dimensions", {
|
|
84
|
+
cause: err
|
|
85
|
+
});
|
|
102
86
|
}
|
|
103
|
-
|
|
104
|
-
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/media/imageCacheCodec.ts
|
|
90
|
+
function isImageValueWire(v) {
|
|
91
|
+
if (v === null || typeof v !== "object")
|
|
92
|
+
return false;
|
|
93
|
+
const o = v;
|
|
94
|
+
return o.__imageValueWire === 1 && typeof o.base64 === "string" && (o.format === "png" || o.format === "jpeg" || o.format === "raw-rgba") && typeof o.width === "number" && typeof o.height === "number" && typeof o.previewScale === "number";
|
|
95
|
+
}
|
|
96
|
+
function bytesToBase64(bytes) {
|
|
97
|
+
if (typeof Buffer !== "undefined") {
|
|
98
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
105
99
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
let bin = "";
|
|
101
|
+
for (let i = 0;i < bytes.length; i++)
|
|
102
|
+
bin += String.fromCharCode(bytes[i] ?? 0);
|
|
103
|
+
return btoa(bin);
|
|
104
|
+
}
|
|
105
|
+
function base64ToBytes(b64) {
|
|
106
|
+
if (typeof Buffer !== "undefined") {
|
|
107
|
+
const buf = Buffer.from(b64, "base64");
|
|
108
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
109
109
|
}
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const bin = atob(b64);
|
|
111
|
+
const out = new Uint8Array(bin.length);
|
|
112
|
+
for (let i = 0;i < bin.length; i++)
|
|
113
|
+
out[i] = bin.charCodeAt(i);
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
async function browserToPngBase64(value) {
|
|
117
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
118
|
+
throw new Error("imageCacheCodec.serialize: BrowserImageValue requires OffscreenCanvas");
|
|
112
119
|
}
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
const off = new OffscreenCanvas(value.width, value.height);
|
|
121
|
+
const ctx = off.getContext("2d");
|
|
122
|
+
if (!ctx)
|
|
123
|
+
throw new Error("imageCacheCodec.serialize: could not acquire 2D context");
|
|
124
|
+
ctx.drawImage(value.bitmap, 0, 0);
|
|
125
|
+
const blob = await off.convertToBlob({ type: "image/png" });
|
|
126
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
127
|
+
return bytesToBase64(bytes);
|
|
128
|
+
}
|
|
129
|
+
async function wireToBrowserImageValue(wire) {
|
|
130
|
+
if (typeof createImageBitmap !== "function") {
|
|
131
|
+
throw new Error("imageCacheCodec.deserialize: browser path requires createImageBitmap");
|
|
115
132
|
}
|
|
116
|
-
|
|
133
|
+
const bytes = base64ToBytes(wire.base64);
|
|
134
|
+
if (wire.format === "raw-rgba") {
|
|
117
135
|
if (typeof ImageData === "undefined") {
|
|
118
|
-
throw new Error("
|
|
136
|
+
throw new Error("imageCacheCodec.deserialize: raw-rgba decode requires ImageData");
|
|
119
137
|
}
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (canvas.height !== this.bin.height)
|
|
125
|
-
canvas.height = this.bin.height;
|
|
126
|
-
const ctx = canvas.getContext("2d");
|
|
127
|
-
if (!ctx)
|
|
128
|
-
throw new Error("CpuImage.toCanvas could not acquire a 2D context");
|
|
129
|
-
ctx.putImageData(id, 0, 0);
|
|
130
|
-
}
|
|
131
|
-
async encode(format, _quality) {
|
|
132
|
-
const codec = getImageRasterCodec();
|
|
133
|
-
const dataUri = await codec.encodeDataUri(this.bin, FORMAT_TO_MIME[format]);
|
|
134
|
-
return dataUriToBytes(dataUri);
|
|
135
|
-
}
|
|
136
|
-
retain(_n = 1) {
|
|
137
|
-
return this;
|
|
138
|
-
}
|
|
139
|
-
release() {}
|
|
140
|
-
static fromImageBinary(bin, previewScale = 1) {
|
|
141
|
-
return new CpuImage(bin, previewScale);
|
|
138
|
+
const data = new Uint8ClampedArray(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
139
|
+
const imageData = new ImageData(data, wire.width, wire.height);
|
|
140
|
+
const bitmap2 = await createImageBitmap(imageData);
|
|
141
|
+
return { bitmap: bitmap2, width: wire.width, height: wire.height, previewScale: wire.previewScale };
|
|
142
142
|
}
|
|
143
|
+
const mime = wire.format === "jpeg" ? "image/jpeg" : "image/png";
|
|
144
|
+
const blob = new Blob([bytes.buffer], { type: mime });
|
|
145
|
+
const bitmap = await createImageBitmap(blob);
|
|
146
|
+
return { bitmap, width: wire.width, height: wire.height, previewScale: wire.previewScale };
|
|
143
147
|
}
|
|
144
|
-
registerGpuImageFactory("fromImageBinary", CpuImage.fromImageBinary);
|
|
145
|
-
|
|
146
|
-
// src/media/imageCacheCodec.ts
|
|
147
148
|
registerPortCodec("image", {
|
|
148
149
|
async serialize(value) {
|
|
149
|
-
if (typeof value
|
|
150
|
+
if (typeof value === "string")
|
|
150
151
|
return value;
|
|
152
|
+
if (isNodeImageValue(value)) {
|
|
153
|
+
return {
|
|
154
|
+
__imageValueWire: 1,
|
|
155
|
+
format: value.format,
|
|
156
|
+
base64: value.buffer.toString("base64"),
|
|
157
|
+
width: value.width,
|
|
158
|
+
height: value.height,
|
|
159
|
+
previewScale: value.previewScale
|
|
160
|
+
};
|
|
151
161
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
162
|
+
if (isBrowserImageValue(value)) {
|
|
163
|
+
const base64 = await browserToPngBase64(value);
|
|
164
|
+
return {
|
|
165
|
+
__imageValueWire: 1,
|
|
166
|
+
format: "png",
|
|
167
|
+
base64,
|
|
168
|
+
width: value.width,
|
|
169
|
+
height: value.height,
|
|
170
|
+
previewScale: value.previewScale
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
throw new Error("imageCacheCodec.serialize: value is not an ImageValue or string");
|
|
160
174
|
},
|
|
161
|
-
async deserialize(
|
|
162
|
-
if (
|
|
163
|
-
return
|
|
175
|
+
async deserialize(wire) {
|
|
176
|
+
if (typeof wire === "string")
|
|
177
|
+
return wire;
|
|
178
|
+
if (!isImageValueWire(wire)) {
|
|
179
|
+
throw new Error("imageCacheCodec.deserialize: input is not an ImageValueWire or string");
|
|
164
180
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
channels: cached.channels
|
|
170
|
-
});
|
|
181
|
+
if (typeof Buffer !== "undefined") {
|
|
182
|
+
return imageValueFromBuffer(Buffer.from(wire.base64, "base64"), wire.format, wire.width, wire.height, wire.previewScale);
|
|
183
|
+
}
|
|
184
|
+
return wireToBrowserImageValue(wire);
|
|
171
185
|
}
|
|
172
186
|
});
|
|
173
187
|
|
|
@@ -177,17 +191,17 @@ class Container {
|
|
|
177
191
|
factories = new Map;
|
|
178
192
|
singletons = new Set;
|
|
179
193
|
resolving = [];
|
|
180
|
-
register(token,
|
|
181
|
-
this.factories.set(token,
|
|
194
|
+
register(token, factory, singleton = true) {
|
|
195
|
+
this.factories.set(token, factory);
|
|
182
196
|
if (singleton) {
|
|
183
197
|
this.singletons.add(token);
|
|
184
198
|
}
|
|
185
199
|
}
|
|
186
|
-
registerIfAbsent(token,
|
|
200
|
+
registerIfAbsent(token, factory, singleton = true) {
|
|
187
201
|
if (this.factories.has(token) || this.services.has(token)) {
|
|
188
202
|
return;
|
|
189
203
|
}
|
|
190
|
-
this.register(token,
|
|
204
|
+
this.register(token, factory, singleton);
|
|
191
205
|
}
|
|
192
206
|
registerInstance(token, instance) {
|
|
193
207
|
this.services.set(token, instance);
|
|
@@ -197,8 +211,8 @@ class Container {
|
|
|
197
211
|
if (this.services.has(token)) {
|
|
198
212
|
return this.services.get(token);
|
|
199
213
|
}
|
|
200
|
-
const
|
|
201
|
-
if (!
|
|
214
|
+
const factory = this.factories.get(token);
|
|
215
|
+
if (!factory) {
|
|
202
216
|
throw new Error(`Service not registered: ${String(token)}`);
|
|
203
217
|
}
|
|
204
218
|
if (this.resolving.includes(token)) {
|
|
@@ -207,7 +221,7 @@ class Container {
|
|
|
207
221
|
}
|
|
208
222
|
this.resolving.push(token);
|
|
209
223
|
try {
|
|
210
|
-
const instance =
|
|
224
|
+
const instance = factory();
|
|
211
225
|
if (this.singletons.has(token)) {
|
|
212
226
|
this.services.set(token, instance);
|
|
213
227
|
}
|
|
@@ -256,8 +270,8 @@ class Container {
|
|
|
256
270
|
}
|
|
257
271
|
createChildContainer() {
|
|
258
272
|
const child = new Container;
|
|
259
|
-
this.factories.forEach((
|
|
260
|
-
child.factories.set(token,
|
|
273
|
+
this.factories.forEach((factory, token) => {
|
|
274
|
+
child.factories.set(token, factory);
|
|
261
275
|
if (this.singletons.has(token)) {
|
|
262
276
|
child.singletons.add(token);
|
|
263
277
|
}
|
|
@@ -272,11 +286,11 @@ class Container {
|
|
|
272
286
|
}
|
|
273
287
|
}
|
|
274
288
|
var GLOBAL_CONTAINER_KEY = Symbol.for("@workglow/util/di/globalContainer");
|
|
275
|
-
var
|
|
276
|
-
if (!
|
|
277
|
-
|
|
289
|
+
var _g2 = globalThis;
|
|
290
|
+
if (!_g2[GLOBAL_CONTAINER_KEY]) {
|
|
291
|
+
_g2[GLOBAL_CONTAINER_KEY] = new Container;
|
|
278
292
|
}
|
|
279
|
-
var globalContainer =
|
|
293
|
+
var globalContainer = _g2[GLOBAL_CONTAINER_KEY];
|
|
280
294
|
|
|
281
295
|
// src/di/ServiceRegistry.ts
|
|
282
296
|
function createServiceToken(id) {
|
|
@@ -288,11 +302,11 @@ class ServiceRegistry {
|
|
|
288
302
|
constructor(container = globalContainer) {
|
|
289
303
|
this.container = container;
|
|
290
304
|
}
|
|
291
|
-
register(token,
|
|
292
|
-
this.container.register(token.id,
|
|
305
|
+
register(token, factory, singleton = true) {
|
|
306
|
+
this.container.register(token.id, factory, singleton);
|
|
293
307
|
}
|
|
294
|
-
registerIfAbsent(token,
|
|
295
|
-
this.container.registerIfAbsent(token.id,
|
|
308
|
+
registerIfAbsent(token, factory, singleton = true) {
|
|
309
|
+
this.container.registerIfAbsent(token.id, factory, singleton);
|
|
296
310
|
}
|
|
297
311
|
registerInstance(token, instance) {
|
|
298
312
|
this.container.registerInstance(token.id, instance);
|
|
@@ -321,16 +335,17 @@ function registerInputResolver(formatPrefix, resolver) {
|
|
|
321
335
|
}
|
|
322
336
|
|
|
323
337
|
// src/media/imageHydrationResolver.ts
|
|
324
|
-
async function
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
338
|
+
async function resolveImage(id, _format, _registry) {
|
|
339
|
+
const normalized = await normalizeToImageValue(id);
|
|
340
|
+
if (normalized !== undefined)
|
|
341
|
+
return normalized;
|
|
342
|
+
if (typeof id === "string") {
|
|
343
|
+
const preview = id.length > 32 ? `${id.slice(0, 32)}...` : id;
|
|
344
|
+
throw new Error(`format:"image" resolver received an unsupported string "${preview}". ` + `Only data: URIs are handled. Register a sub-resolver for other schemes.`);
|
|
329
345
|
}
|
|
330
|
-
|
|
331
|
-
throw new Error(`format:"image" resolver received an unsupported string "${preview}". ` + `Only data: URIs are handled. For other schemes register a sub-resolver, ` + `e.g. registerInputResolver("image:http", fn).`);
|
|
346
|
+
return id;
|
|
332
347
|
}
|
|
333
|
-
registerInputResolver("image",
|
|
348
|
+
registerInputResolver("image", resolveImage);
|
|
334
349
|
|
|
335
350
|
// src/media/color.ts
|
|
336
351
|
var HEX_PATTERN = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
@@ -440,8 +455,153 @@ function resolveColor(value) {
|
|
|
440
455
|
a: value.a ?? 255
|
|
441
456
|
};
|
|
442
457
|
}
|
|
458
|
+
// src/media/cpuImage.ts
|
|
459
|
+
var FORMAT_TO_MIME = {
|
|
460
|
+
png: "image/png",
|
|
461
|
+
jpeg: "image/jpeg",
|
|
462
|
+
webp: "image/webp"
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
class CpuImage {
|
|
466
|
+
bin;
|
|
467
|
+
backend = "cpu";
|
|
468
|
+
constructor(bin) {
|
|
469
|
+
this.bin = bin;
|
|
470
|
+
}
|
|
471
|
+
get width() {
|
|
472
|
+
if (!this.bin)
|
|
473
|
+
throw new Error("CpuImage.width on a disposed image");
|
|
474
|
+
return this.bin.width;
|
|
475
|
+
}
|
|
476
|
+
get height() {
|
|
477
|
+
if (!this.bin)
|
|
478
|
+
throw new Error("CpuImage.height on a disposed image");
|
|
479
|
+
return this.bin.height;
|
|
480
|
+
}
|
|
481
|
+
get channels() {
|
|
482
|
+
if (!this.bin)
|
|
483
|
+
throw new Error("CpuImage.channels on a disposed image");
|
|
484
|
+
return this.bin.channels;
|
|
485
|
+
}
|
|
486
|
+
getBinary() {
|
|
487
|
+
if (!this.bin)
|
|
488
|
+
throw new Error("CpuImage.getBinary on a disposed image");
|
|
489
|
+
return this.bin;
|
|
490
|
+
}
|
|
491
|
+
static async from(value) {
|
|
492
|
+
if (isBrowserImageValue(value)) {
|
|
493
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
494
|
+
throw new Error("CpuImage.from(BrowserImageValue) requires OffscreenCanvas");
|
|
495
|
+
}
|
|
496
|
+
const off = new OffscreenCanvas(value.width, value.height);
|
|
497
|
+
const ctx = off.getContext("2d");
|
|
498
|
+
if (!ctx)
|
|
499
|
+
throw new Error("CpuImage.from: could not acquire 2D context");
|
|
500
|
+
ctx.drawImage(value.bitmap, 0, 0);
|
|
501
|
+
const id = ctx.getImageData(0, 0, value.width, value.height);
|
|
502
|
+
return new CpuImage({ data: id.data, width: value.width, height: value.height, channels: 4 });
|
|
503
|
+
}
|
|
504
|
+
if (isNodeImageValue(value)) {
|
|
505
|
+
const bin = await decodeNodeImageValue(value);
|
|
506
|
+
return new CpuImage(bin);
|
|
507
|
+
}
|
|
508
|
+
throw new Error("CpuImage.from: unrecognized ImageValue shape");
|
|
509
|
+
}
|
|
510
|
+
static fromRaw(bin) {
|
|
511
|
+
return new CpuImage(bin);
|
|
512
|
+
}
|
|
513
|
+
async toImageValue(previewScale) {
|
|
514
|
+
if (!this.bin)
|
|
515
|
+
throw new Error("CpuImage.toImageValue on a disposed image");
|
|
516
|
+
if (typeof OffscreenCanvas !== "undefined" && typeof createImageBitmap === "function") {
|
|
517
|
+
const off = new OffscreenCanvas(this.bin.width, this.bin.height);
|
|
518
|
+
const ctx = off.getContext("2d");
|
|
519
|
+
if (!ctx)
|
|
520
|
+
throw new Error("CpuImage.toImageValue could not acquire a 2D context");
|
|
521
|
+
const rgba2 = expandToRgba(this.bin);
|
|
522
|
+
ctx.putImageData(new ImageData(new Uint8ClampedArray(rgba2.buffer, rgba2.byteOffset, rgba2.byteLength), this.bin.width, this.bin.height), 0, 0);
|
|
523
|
+
const bitmap = await createImageBitmap(off);
|
|
524
|
+
const out2 = {
|
|
525
|
+
bitmap,
|
|
526
|
+
width: this.bin.width,
|
|
527
|
+
height: this.bin.height,
|
|
528
|
+
previewScale
|
|
529
|
+
};
|
|
530
|
+
this.bin = null;
|
|
531
|
+
return out2;
|
|
532
|
+
}
|
|
533
|
+
const rgba = expandToRgba(this.bin);
|
|
534
|
+
const buffer = Buffer.from(rgba.buffer, rgba.byteOffset, rgba.byteLength);
|
|
535
|
+
const out = {
|
|
536
|
+
buffer,
|
|
537
|
+
format: "raw-rgba",
|
|
538
|
+
width: this.bin.width,
|
|
539
|
+
height: this.bin.height,
|
|
540
|
+
previewScale
|
|
541
|
+
};
|
|
542
|
+
this.bin = null;
|
|
543
|
+
return out;
|
|
544
|
+
}
|
|
545
|
+
async encode(format, _quality) {
|
|
546
|
+
if (!this.bin)
|
|
547
|
+
throw new Error("CpuImage.encode on a disposed image");
|
|
548
|
+
const codec = getImageRasterCodec();
|
|
549
|
+
const dataUri = await codec.encodeDataUri(this.bin, FORMAT_TO_MIME[format]);
|
|
550
|
+
return dataUriToBytes(dataUri);
|
|
551
|
+
}
|
|
552
|
+
dispose() {
|
|
553
|
+
this.bin = null;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function expandToRgba(bin) {
|
|
557
|
+
if (bin.channels === 4)
|
|
558
|
+
return bin.data;
|
|
559
|
+
const px = bin.width * bin.height;
|
|
560
|
+
const out = new Uint8ClampedArray(px * 4);
|
|
561
|
+
if (bin.channels === 3) {
|
|
562
|
+
for (let i = 0;i < px; i++) {
|
|
563
|
+
out[i * 4 + 0] = bin.data[i * 3 + 0] ?? 0;
|
|
564
|
+
out[i * 4 + 1] = bin.data[i * 3 + 1] ?? 0;
|
|
565
|
+
out[i * 4 + 2] = bin.data[i * 3 + 2] ?? 0;
|
|
566
|
+
out[i * 4 + 3] = 255;
|
|
567
|
+
}
|
|
568
|
+
} else if (bin.channels === 1) {
|
|
569
|
+
for (let i = 0;i < px; i++) {
|
|
570
|
+
const g = bin.data[i] ?? 0;
|
|
571
|
+
out[i * 4 + 0] = g;
|
|
572
|
+
out[i * 4 + 1] = g;
|
|
573
|
+
out[i * 4 + 2] = g;
|
|
574
|
+
out[i * 4 + 3] = 255;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return out;
|
|
578
|
+
}
|
|
579
|
+
function dataUriToBytes(dataUri) {
|
|
580
|
+
const comma = dataUri.indexOf(",");
|
|
581
|
+
const b64 = dataUri.slice(comma + 1);
|
|
582
|
+
const bin = atob(b64);
|
|
583
|
+
const bytes = new Uint8Array(bin.length);
|
|
584
|
+
for (let i = 0;i < bin.length; i++)
|
|
585
|
+
bytes[i] = bin.charCodeAt(i);
|
|
586
|
+
return bytes;
|
|
587
|
+
}
|
|
588
|
+
async function decodeNodeImageValue(value) {
|
|
589
|
+
if (value.format === "raw-rgba") {
|
|
590
|
+
const data = new Uint8ClampedArray(value.buffer.buffer, value.buffer.byteOffset, value.buffer.byteLength);
|
|
591
|
+
return { data, width: value.width, height: value.height, channels: 4 };
|
|
592
|
+
}
|
|
593
|
+
const codec = getImageRasterCodec();
|
|
594
|
+
const dataUri = `data:image/${value.format};base64,${value.buffer.toString("base64")}`;
|
|
595
|
+
const decoded = await codec.decodeDataUri(dataUri);
|
|
596
|
+
return {
|
|
597
|
+
data: decoded.data,
|
|
598
|
+
width: decoded.width,
|
|
599
|
+
height: decoded.height,
|
|
600
|
+
channels: decoded.channels
|
|
601
|
+
};
|
|
602
|
+
}
|
|
443
603
|
// src/media/encode.ts
|
|
444
|
-
async function
|
|
604
|
+
async function rawPixelBufferToBytes(bin, mimeType) {
|
|
445
605
|
const dataUri = await getImageRasterCodec().encodeDataUri(bin, mimeType);
|
|
446
606
|
const b64 = dataUri.slice(dataUri.indexOf(",") + 1);
|
|
447
607
|
const decoded = atob(b64);
|
|
@@ -450,28 +610,21 @@ async function encodeImageBinaryBytes(bin, mimeType) {
|
|
|
450
610
|
bytes[i] = decoded.charCodeAt(i);
|
|
451
611
|
return bytes;
|
|
452
612
|
}
|
|
453
|
-
async function
|
|
454
|
-
return encodeImageBinaryBytes(bin, "image/png");
|
|
455
|
-
}
|
|
456
|
-
async function imageBinaryToBase64Png(bin) {
|
|
457
|
-
const dataUri = await getImageRasterCodec().encodeDataUri(bin, "image/png");
|
|
458
|
-
return dataUri.slice(dataUri.indexOf(",") + 1);
|
|
459
|
-
}
|
|
460
|
-
async function imageBinaryToDataUri(bin, mimeType = "image/png") {
|
|
613
|
+
async function rawPixelBufferToDataUri(bin, mimeType = "image/png") {
|
|
461
614
|
return getImageRasterCodec().encodeDataUri(bin, mimeType);
|
|
462
615
|
}
|
|
463
|
-
async function
|
|
464
|
-
const bytes = await
|
|
616
|
+
async function rawPixelBufferToBlob(bin, mimeType = "image/png") {
|
|
617
|
+
const bytes = await rawPixelBufferToBytes(bin, mimeType);
|
|
465
618
|
return new Blob([bytes.buffer], { type: mimeType });
|
|
466
619
|
}
|
|
467
620
|
// src/media/filterRegistry.ts
|
|
468
621
|
var GLOBAL_REGISTRY_KEY = Symbol.for("@workglow/util/media/filterRegistry");
|
|
469
|
-
var
|
|
622
|
+
var _g3 = globalThis;
|
|
470
623
|
function getRegistry() {
|
|
471
|
-
let reg =
|
|
624
|
+
let reg = _g3[GLOBAL_REGISTRY_KEY];
|
|
472
625
|
if (!reg) {
|
|
473
626
|
reg = new Map;
|
|
474
|
-
|
|
627
|
+
_g3[GLOBAL_REGISTRY_KEY] = reg;
|
|
475
628
|
}
|
|
476
629
|
return reg;
|
|
477
630
|
}
|
|
@@ -514,28 +667,42 @@ async function getGpuDevice() {
|
|
|
514
667
|
function resetGpuDeviceForTests() {
|
|
515
668
|
cached = null;
|
|
516
669
|
}
|
|
517
|
-
// src/media/
|
|
518
|
-
|
|
670
|
+
// src/media/gpuImage.ts
|
|
671
|
+
var GLOBAL_FACTORY_KEY = Symbol.for("@workglow/util/media/gpuImageFactory");
|
|
672
|
+
var _g4 = globalThis;
|
|
673
|
+
if (!_g4[GLOBAL_FACTORY_KEY]) {
|
|
674
|
+
_g4[GLOBAL_FACTORY_KEY] = {};
|
|
675
|
+
}
|
|
676
|
+
var factory = _g4[GLOBAL_FACTORY_KEY];
|
|
677
|
+
function registerGpuImageFactory(key2, fn) {
|
|
678
|
+
factory[key2] = fn;
|
|
679
|
+
}
|
|
680
|
+
function getGpuImageFactory(key2) {
|
|
681
|
+
const fn = factory[key2];
|
|
682
|
+
return typeof fn === "function" ? fn : undefined;
|
|
683
|
+
}
|
|
684
|
+
var GpuImage = new Proxy({}, {
|
|
685
|
+
get(_t, prop) {
|
|
686
|
+
if (typeof prop !== "string" || prop === "then")
|
|
687
|
+
return;
|
|
688
|
+
const fn = factory[prop];
|
|
689
|
+
if (typeof fn !== "function") {
|
|
690
|
+
throw new Error(`GpuImage.${prop} is not registered. Import the platform entry point.`);
|
|
691
|
+
}
|
|
692
|
+
return fn;
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
// src/media/imageValueSchema.ts
|
|
696
|
+
function ImageValueSchema(annotations = {}) {
|
|
519
697
|
return {
|
|
520
698
|
type: ["string", "object"],
|
|
521
699
|
properties: {},
|
|
522
700
|
title: "Image",
|
|
523
|
-
description: "Image (hydrated to
|
|
701
|
+
description: "Image (hydrated to ImageValue at task entry)",
|
|
524
702
|
...annotations,
|
|
525
703
|
format: "image"
|
|
526
704
|
};
|
|
527
705
|
}
|
|
528
|
-
// src/media/imageTypes.ts
|
|
529
|
-
function parseDataUri(dataUri) {
|
|
530
|
-
const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);
|
|
531
|
-
if (!match) {
|
|
532
|
-
throw new Error("Invalid base64 data URI");
|
|
533
|
-
}
|
|
534
|
-
return {
|
|
535
|
-
mimeType: match[1],
|
|
536
|
-
base64: match[2]
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
706
|
// src/media/MediaRawImage.ts
|
|
540
707
|
class MediaRawImage {
|
|
541
708
|
data;
|
|
@@ -578,9 +745,7 @@ function setPreviewBudget(px) {
|
|
|
578
745
|
}
|
|
579
746
|
_g5[GLOBAL_BUDGET_KEY] = Math.floor(px);
|
|
580
747
|
}
|
|
581
|
-
function previewSource(image) {
|
|
582
|
-
if (image.backend !== "webgpu")
|
|
583
|
-
return image;
|
|
748
|
+
async function previewSource(image) {
|
|
584
749
|
const budget = getPreviewBudget();
|
|
585
750
|
const long = Math.max(image.width, image.height);
|
|
586
751
|
if (long <= budget)
|
|
@@ -589,9 +754,14 @@ function previewSource(image) {
|
|
|
589
754
|
const resize = getPreviewResizeFn();
|
|
590
755
|
if (!resize)
|
|
591
756
|
return image;
|
|
592
|
-
const
|
|
593
|
-
const
|
|
594
|
-
|
|
757
|
+
const targetW = Math.max(1, Math.round(image.width * ratio));
|
|
758
|
+
const targetH = Math.max(1, Math.round(image.height * ratio));
|
|
759
|
+
const result = await resize(image, targetW, targetH);
|
|
760
|
+
const composedScale = image.previewScale * ratio;
|
|
761
|
+
return {
|
|
762
|
+
...result,
|
|
763
|
+
previewScale: composedScale
|
|
764
|
+
};
|
|
595
765
|
}
|
|
596
766
|
// src/media/shaderRegistry.browser.ts
|
|
597
767
|
var VERTEX_PRELUDE = `
|
|
@@ -708,37 +878,6 @@ function resetTexturePoolForTests() {
|
|
|
708
878
|
}
|
|
709
879
|
// src/media/webGpuImage.browser.ts
|
|
710
880
|
var TEX_FORMAT = "rgba8unorm";
|
|
711
|
-
var finalizers = typeof FinalizationRegistry !== "undefined" ? new FinalizationRegistry((fn) => {
|
|
712
|
-
try {
|
|
713
|
-
fn();
|
|
714
|
-
} catch {}
|
|
715
|
-
}) : undefined;
|
|
716
|
-
function expandToRgba2(bin) {
|
|
717
|
-
if (bin.channels === 4)
|
|
718
|
-
return bin.data;
|
|
719
|
-
const px = bin.width * bin.height;
|
|
720
|
-
const out = new Uint8ClampedArray(px * 4);
|
|
721
|
-
if (bin.channels === 3) {
|
|
722
|
-
for (let i = 0;i < px; i++) {
|
|
723
|
-
out[i * 4 + 0] = bin.data[i * 3 + 0] ?? 0;
|
|
724
|
-
out[i * 4 + 1] = bin.data[i * 3 + 1] ?? 0;
|
|
725
|
-
out[i * 4 + 2] = bin.data[i * 3 + 2] ?? 0;
|
|
726
|
-
out[i * 4 + 3] = 255;
|
|
727
|
-
}
|
|
728
|
-
} else if (bin.channels === 1) {
|
|
729
|
-
for (let i = 0;i < px; i++) {
|
|
730
|
-
const g = bin.data[i] ?? 0;
|
|
731
|
-
out[i * 4 + 0] = g;
|
|
732
|
-
out[i * 4 + 1] = g;
|
|
733
|
-
out[i * 4 + 2] = g;
|
|
734
|
-
out[i * 4 + 3] = 255;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
return out;
|
|
738
|
-
}
|
|
739
|
-
function align(n, m) {
|
|
740
|
-
return Math.ceil(n / m) * m;
|
|
741
|
-
}
|
|
742
881
|
|
|
743
882
|
class WebGpuImage {
|
|
744
883
|
device;
|
|
@@ -747,43 +886,29 @@ class WebGpuImage {
|
|
|
747
886
|
height;
|
|
748
887
|
backend = "webgpu";
|
|
749
888
|
channels = 4;
|
|
750
|
-
|
|
751
|
-
_previewScale;
|
|
752
|
-
constructor(device, texture, width, height, previewScale = 1) {
|
|
889
|
+
constructor(device, texture, width, height) {
|
|
753
890
|
this.device = device;
|
|
754
891
|
this.texture = texture;
|
|
755
892
|
this.width = width;
|
|
756
893
|
this.height = height;
|
|
757
|
-
this._previewScale = previewScale;
|
|
758
|
-
if (finalizers && texture) {
|
|
759
|
-
const dev = device;
|
|
760
|
-
const tex = texture;
|
|
761
|
-
finalizers.register(this, () => {
|
|
762
|
-
try {
|
|
763
|
-
getTexturePool(dev).release(tex);
|
|
764
|
-
} catch {}
|
|
765
|
-
}, this);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
get previewScale() {
|
|
769
|
-
return this._previewScale;
|
|
770
894
|
}
|
|
771
|
-
|
|
772
|
-
this._previewScale = scale;
|
|
773
|
-
return this;
|
|
774
|
-
}
|
|
775
|
-
static async fromImageBinary(bin) {
|
|
895
|
+
static async from(value) {
|
|
776
896
|
const dev = await getGpuDevice();
|
|
777
897
|
if (!dev)
|
|
778
|
-
throw new Error("WebGPU device unavailable
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
898
|
+
throw new Error("WebGpuImage.from: WebGPU device unavailable");
|
|
899
|
+
if (isNodeImageValue(value)) {
|
|
900
|
+
throw new Error("WebGpuImage.from: NodeImageValue not supported in browser runtime");
|
|
901
|
+
}
|
|
902
|
+
if (!isBrowserImageValue(value)) {
|
|
903
|
+
throw new Error("WebGpuImage.from: unrecognized ImageValue shape");
|
|
904
|
+
}
|
|
905
|
+
const tex = getTexturePool(dev).acquire(value.width, value.height, TEX_FORMAT);
|
|
906
|
+
dev.queue.copyExternalImageToTexture({ source: value.bitmap }, { texture: tex }, [value.width, value.height, 1]);
|
|
907
|
+
return new WebGpuImage(dev, tex, value.width, value.height);
|
|
783
908
|
}
|
|
784
909
|
apply(params) {
|
|
785
910
|
if (!this.texture)
|
|
786
|
-
throw new Error("WebGpuImage.apply called on a
|
|
911
|
+
throw new Error("WebGpuImage.apply called on a disposed image");
|
|
787
912
|
const outW = params.outSize?.width ?? this.width;
|
|
788
913
|
const outH = params.outSize?.height ?? this.height;
|
|
789
914
|
const out = getTexturePool(this.device).acquire(outW, outH, TEX_FORMAT);
|
|
@@ -825,44 +950,18 @@ class WebGpuImage {
|
|
|
825
950
|
pass.draw(3);
|
|
826
951
|
pass.end();
|
|
827
952
|
this.device.queue.submit([enc.finish()]);
|
|
828
|
-
return new WebGpuImage(this.device, out, outW, outH
|
|
953
|
+
return new WebGpuImage(this.device, out, outW, outH);
|
|
829
954
|
}
|
|
830
|
-
async
|
|
955
|
+
async transferToImageBitmap() {
|
|
831
956
|
if (!this.texture)
|
|
832
|
-
throw new Error("WebGpuImage.
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
size: bytesPerRow * this.height,
|
|
836
|
-
usage: 1 | 8
|
|
837
|
-
});
|
|
838
|
-
const enc = this.device.createCommandEncoder();
|
|
839
|
-
enc.copyTextureToBuffer({ texture: this.texture }, { buffer, bytesPerRow, rowsPerImage: this.height }, [this.width, this.height, 1]);
|
|
840
|
-
this.device.queue.submit([enc.finish()]);
|
|
841
|
-
await buffer.mapAsync(1);
|
|
842
|
-
const mapped = new Uint8Array(buffer.getMappedRange());
|
|
843
|
-
const tightStride = this.width * 4;
|
|
844
|
-
const tight = new Uint8ClampedArray(this.width * this.height * 4);
|
|
845
|
-
if (bytesPerRow === tightStride) {
|
|
846
|
-
tight.set(mapped);
|
|
847
|
-
} else {
|
|
848
|
-
for (let y = 0;y < this.height; y++) {
|
|
849
|
-
tight.set(mapped.subarray(y * bytesPerRow, y * bytesPerRow + tightStride), y * tightStride);
|
|
850
|
-
}
|
|
957
|
+
throw new Error("WebGpuImage.transferToImageBitmap on a disposed image");
|
|
958
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
959
|
+
throw new Error("WebGpuImage.transferToImageBitmap requires OffscreenCanvas");
|
|
851
960
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
return { data: tight, width: this.width, height: this.height, channels: 4 };
|
|
855
|
-
}
|
|
856
|
-
async toCanvas(canvas) {
|
|
857
|
-
if (!this.texture)
|
|
858
|
-
throw new Error("WebGpuImage.toCanvas called on a released image");
|
|
859
|
-
if (canvas.width !== this.width)
|
|
860
|
-
canvas.width = this.width;
|
|
861
|
-
if (canvas.height !== this.height)
|
|
862
|
-
canvas.height = this.height;
|
|
863
|
-
const ctx = canvas.getContext("webgpu");
|
|
961
|
+
const off = new OffscreenCanvas(this.width, this.height);
|
|
962
|
+
const ctx = off.getContext("webgpu");
|
|
864
963
|
if (!ctx)
|
|
865
|
-
throw new Error("WebGpuImage.
|
|
964
|
+
throw new Error("WebGpuImage.transferToImageBitmap: no webgpu context");
|
|
866
965
|
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
867
966
|
ctx.configure({ device: this.device, format: presentationFormat, alphaMode: "premultiplied" });
|
|
868
967
|
const view = ctx.getCurrentTexture().createView();
|
|
@@ -890,72 +989,54 @@ class WebGpuImage {
|
|
|
890
989
|
pass.draw(3);
|
|
891
990
|
pass.end();
|
|
892
991
|
this.device.queue.submit([enc.finish()]);
|
|
992
|
+
try {
|
|
993
|
+
return await createImageBitmap(off);
|
|
994
|
+
} finally {
|
|
995
|
+
this.dispose();
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
async toImageValue(previewScale) {
|
|
999
|
+
const bitmap = await this.transferToImageBitmap();
|
|
1000
|
+
return imageValueFromBitmap(bitmap, this.width, this.height, previewScale);
|
|
893
1001
|
}
|
|
894
1002
|
async encode(format, quality) {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
throw new Error("WebGpuImage.encode requires an OffscreenCanvas environment");
|
|
898
|
-
}
|
|
1003
|
+
if (!this.texture)
|
|
1004
|
+
throw new Error("WebGpuImage.encode on a disposed image");
|
|
899
1005
|
const off = new OffscreenCanvas(this.width, this.height);
|
|
900
1006
|
const ctx = off.getContext("2d");
|
|
901
1007
|
if (!ctx)
|
|
902
1008
|
throw new Error("WebGpuImage.encode could not acquire a 2D context");
|
|
903
|
-
|
|
1009
|
+
const bitmap = await this.transferToImageBitmap();
|
|
1010
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
904
1011
|
const blob = await off.convertToBlob({ type: `image/${format}`, quality });
|
|
905
1012
|
return new Uint8Array(await blob.arrayBuffer());
|
|
906
1013
|
}
|
|
907
|
-
|
|
908
|
-
if (this.
|
|
909
|
-
throw new Error("WebGpuImage.retain called on a released image");
|
|
910
|
-
}
|
|
911
|
-
this.refcount += n;
|
|
912
|
-
return this;
|
|
913
|
-
}
|
|
914
|
-
release() {
|
|
915
|
-
if (this.refcount <= 0) {
|
|
916
|
-
throw new Error("WebGpuImage.release called on a released image");
|
|
917
|
-
}
|
|
918
|
-
this.refcount -= 1;
|
|
919
|
-
if (this.refcount > 0)
|
|
1014
|
+
dispose() {
|
|
1015
|
+
if (!this.texture)
|
|
920
1016
|
return;
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if (finalizers)
|
|
925
|
-
finalizers.unregister(this);
|
|
1017
|
+
const tex = this.texture;
|
|
1018
|
+
this.texture = null;
|
|
1019
|
+
try {
|
|
926
1020
|
getTexturePool(this.device).release(tex);
|
|
927
|
-
}
|
|
1021
|
+
} catch {}
|
|
928
1022
|
}
|
|
929
1023
|
}
|
|
1024
|
+
registerGpuImageFactory("from", WebGpuImage.from.bind(WebGpuImage));
|
|
930
1025
|
// src/media-browser.ts
|
|
931
|
-
async function
|
|
1026
|
+
async function probeImageDimensions() {
|
|
1027
|
+
throw new Error("probeImageDimensions: not available in browser runtime");
|
|
1028
|
+
}
|
|
1029
|
+
async function decodeBufferToRaw() {
|
|
1030
|
+
throw new Error("decodeBufferToRaw: not available in browser runtime");
|
|
1031
|
+
}
|
|
1032
|
+
async function encodeRawPixels() {
|
|
1033
|
+
throw new Error("encodeRawPixels: not available in browser runtime");
|
|
1034
|
+
}
|
|
1035
|
+
async function _preferGpu(value) {
|
|
932
1036
|
const dev = await getGpuDevice();
|
|
933
|
-
return dev ? WebGpuImage.
|
|
1037
|
+
return dev ? WebGpuImage.from(value) : CpuImage.from(value);
|
|
934
1038
|
}
|
|
935
|
-
registerGpuImageFactory("
|
|
936
|
-
registerGpuImageFactory("fromDataUri", async (dataUri) => {
|
|
937
|
-
const bin = await getImageRasterCodec().decodeDataUri(dataUri);
|
|
938
|
-
return _preferGpu(bin);
|
|
939
|
-
});
|
|
940
|
-
registerGpuImageFactory("fromBlob", async (blob) => {
|
|
941
|
-
const bitmap = await createImageBitmap(blob);
|
|
942
|
-
const off = new OffscreenCanvas(bitmap.width, bitmap.height);
|
|
943
|
-
const ctx = off.getContext("2d");
|
|
944
|
-
if (!ctx)
|
|
945
|
-
throw new Error("fromBlob: could not acquire 2D context");
|
|
946
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
947
|
-
const id = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
948
|
-
return _preferGpu({ data: id.data, width: bitmap.width, height: bitmap.height, channels: 4 });
|
|
949
|
-
});
|
|
950
|
-
registerGpuImageFactory("fromImageBitmap", async (bitmap) => {
|
|
951
|
-
const off = new OffscreenCanvas(bitmap.width, bitmap.height);
|
|
952
|
-
const ctx = off.getContext("2d");
|
|
953
|
-
if (!ctx)
|
|
954
|
-
throw new Error("fromImageBitmap: could not acquire 2D context");
|
|
955
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
956
|
-
const id = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
957
|
-
return _preferGpu({ data: id.data, width: bitmap.width, height: bitmap.height, channels: 4 });
|
|
958
|
-
});
|
|
1039
|
+
registerGpuImageFactory("from", _preferGpu);
|
|
959
1040
|
export {
|
|
960
1041
|
toHexColor,
|
|
961
1042
|
setPreviewBudget,
|
|
@@ -966,15 +1047,20 @@ export {
|
|
|
966
1047
|
registerImageRasterCodec,
|
|
967
1048
|
registerGpuImageFactory,
|
|
968
1049
|
registerFilterOp,
|
|
1050
|
+
rawPixelBufferToDataUri,
|
|
1051
|
+
rawPixelBufferToBlob,
|
|
1052
|
+
probeImageDimensions,
|
|
969
1053
|
previewSource,
|
|
970
1054
|
parseHexColor,
|
|
971
|
-
|
|
1055
|
+
normalizeToImageValue,
|
|
1056
|
+
isNodeImageValue,
|
|
972
1057
|
isMediaRawImageShape,
|
|
1058
|
+
isImageValue,
|
|
973
1059
|
isHexColor,
|
|
974
1060
|
isColorObject,
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1061
|
+
isBrowserImageValue,
|
|
1062
|
+
imageValueFromBuffer,
|
|
1063
|
+
imageValueFromBitmap,
|
|
978
1064
|
hasFilterOp,
|
|
979
1065
|
getTexturePool,
|
|
980
1066
|
getShaderCache,
|
|
@@ -982,7 +1068,8 @@ export {
|
|
|
982
1068
|
getImageRasterCodec,
|
|
983
1069
|
getGpuImageFactory,
|
|
984
1070
|
getGpuDevice,
|
|
985
|
-
|
|
1071
|
+
encodeRawPixels,
|
|
1072
|
+
decodeBufferToRaw,
|
|
986
1073
|
createTexturePool,
|
|
987
1074
|
createShaderCache,
|
|
988
1075
|
applyFilter,
|
|
@@ -991,9 +1078,9 @@ export {
|
|
|
991
1078
|
VERTEX_PRELUDE,
|
|
992
1079
|
PASSTHROUGH_SHADER_SRC,
|
|
993
1080
|
MediaRawImage,
|
|
994
|
-
|
|
1081
|
+
ImageValueSchema,
|
|
995
1082
|
GpuImage as GpuImageFactory,
|
|
996
1083
|
CpuImage
|
|
997
1084
|
};
|
|
998
1085
|
|
|
999
|
-
//# debugId=
|
|
1086
|
+
//# debugId=4003D4BA5EB9040764756E2164756E21
|