@workglow/util 0.2.20 → 0.2.22
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 +5 -2
- package/dist/browser.js.map +3 -3
- package/dist/bun.js +5 -2
- package/dist/bun.js.map +3 -3
- 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 +5 -2
- package/dist/node.js.map +3 -3
- package/dist/schema-entry.js +166 -165
- package/dist/schema-entry.js.map +5 -5
- 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-node.js
CHANGED
|
@@ -4,39 +4,13 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
4
4
|
// src/media/imageCacheCodec.ts
|
|
5
5
|
import { registerPortCodec } from "@workglow/util";
|
|
6
6
|
|
|
7
|
-
// src/media/gpuImage.ts
|
|
8
|
-
var GLOBAL_FACTORY_KEY = Symbol.for("@workglow/util/media/gpuImageFactory");
|
|
9
|
-
var _g = globalThis;
|
|
10
|
-
if (!_g[GLOBAL_FACTORY_KEY]) {
|
|
11
|
-
_g[GLOBAL_FACTORY_KEY] = {};
|
|
12
|
-
}
|
|
13
|
-
var factory = _g[GLOBAL_FACTORY_KEY];
|
|
14
|
-
function registerGpuImageFactory(key, fn) {
|
|
15
|
-
factory[key] = fn;
|
|
16
|
-
}
|
|
17
|
-
function getGpuImageFactory(key) {
|
|
18
|
-
const fn = factory[key];
|
|
19
|
-
return typeof fn === "function" ? fn : undefined;
|
|
20
|
-
}
|
|
21
|
-
var GpuImage = new Proxy({}, {
|
|
22
|
-
get(_t, prop) {
|
|
23
|
-
if (typeof prop !== "string" || prop === "then")
|
|
24
|
-
return;
|
|
25
|
-
const fn = factory[prop];
|
|
26
|
-
if (typeof fn !== "function") {
|
|
27
|
-
throw new Error(`GpuImage.${prop} is not registered. Import the platform entry point.`);
|
|
28
|
-
}
|
|
29
|
-
return fn;
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
|
|
33
7
|
// src/media/imageRasterCodecRegistry.ts
|
|
34
8
|
var GLOBAL_CODEC_KEY = Symbol.for("@workglow/util/media/imageRasterCodec");
|
|
35
|
-
var
|
|
36
|
-
if (!
|
|
37
|
-
|
|
9
|
+
var _g = globalThis;
|
|
10
|
+
if (!_g[GLOBAL_CODEC_KEY]) {
|
|
11
|
+
_g[GLOBAL_CODEC_KEY] = { value: null };
|
|
38
12
|
}
|
|
39
|
-
var slot =
|
|
13
|
+
var slot = _g[GLOBAL_CODEC_KEY];
|
|
40
14
|
function registerImageRasterCodec(next) {
|
|
41
15
|
slot.value = next;
|
|
42
16
|
}
|
|
@@ -47,130 +21,170 @@ function getImageRasterCodec() {
|
|
|
47
21
|
return slot.value;
|
|
48
22
|
}
|
|
49
23
|
|
|
50
|
-
// src/media/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
jpeg: "image/jpeg",
|
|
54
|
-
webp: "image/webp"
|
|
55
|
-
};
|
|
56
|
-
function dataUriToBytes(dataUri) {
|
|
57
|
-
const comma = dataUri.indexOf(",");
|
|
58
|
-
const b64 = dataUri.slice(comma + 1);
|
|
59
|
-
const bin = atob(b64);
|
|
60
|
-
const bytes = new Uint8Array(bin.length);
|
|
61
|
-
for (let i = 0;i < bin.length; i++)
|
|
62
|
-
bytes[i] = bin.charCodeAt(i);
|
|
63
|
-
return bytes;
|
|
24
|
+
// src/media/imageValue.ts
|
|
25
|
+
function imageValueFromBitmap(bitmap, width, height, previewScale = 1) {
|
|
26
|
+
return { bitmap, width, height, previewScale };
|
|
64
27
|
}
|
|
65
|
-
function
|
|
66
|
-
|
|
67
|
-
return bin.data;
|
|
68
|
-
const px = bin.width * bin.height;
|
|
69
|
-
const out = new Uint8ClampedArray(px * 4);
|
|
70
|
-
if (bin.channels === 3) {
|
|
71
|
-
for (let i = 0;i < px; i++) {
|
|
72
|
-
out[i * 4 + 0] = bin.data[i * 3 + 0] ?? 0;
|
|
73
|
-
out[i * 4 + 1] = bin.data[i * 3 + 1] ?? 0;
|
|
74
|
-
out[i * 4 + 2] = bin.data[i * 3 + 2] ?? 0;
|
|
75
|
-
out[i * 4 + 3] = 255;
|
|
76
|
-
}
|
|
77
|
-
} else if (bin.channels === 1) {
|
|
78
|
-
for (let i = 0;i < px; i++) {
|
|
79
|
-
const g = bin.data[i] ?? 0;
|
|
80
|
-
out[i * 4 + 0] = g;
|
|
81
|
-
out[i * 4 + 1] = g;
|
|
82
|
-
out[i * 4 + 2] = g;
|
|
83
|
-
out[i * 4 + 3] = 255;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
28
|
+
function imageValueFromBuffer(buffer, format, width, height, previewScale = 1) {
|
|
29
|
+
return { buffer, format, width, height, previewScale };
|
|
87
30
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
31
|
+
function isImageValue(v) {
|
|
32
|
+
return isBrowserImageValue(v) || isNodeImageValue(v);
|
|
33
|
+
}
|
|
34
|
+
function isBrowserImageValue(v) {
|
|
35
|
+
if (v === null || typeof v !== "object")
|
|
36
|
+
return false;
|
|
37
|
+
const o = v;
|
|
38
|
+
return typeof o.width === "number" && typeof o.height === "number" && typeof o.previewScale === "number" && typeof ImageBitmap !== "undefined" && o.bitmap instanceof ImageBitmap;
|
|
39
|
+
}
|
|
40
|
+
function isNodeImageValue(v) {
|
|
41
|
+
if (v === null || typeof v !== "object")
|
|
42
|
+
return false;
|
|
43
|
+
const o = v;
|
|
44
|
+
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");
|
|
45
|
+
}
|
|
46
|
+
async function normalizeToImageValue(value) {
|
|
47
|
+
if (value === null || value === undefined)
|
|
48
|
+
return;
|
|
49
|
+
if (isImageValue(value))
|
|
50
|
+
return value;
|
|
51
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
52
|
+
if (typeof createImageBitmap === "function") {
|
|
53
|
+
const bitmap = await createImageBitmap(value);
|
|
54
|
+
return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
96
57
|
}
|
|
97
|
-
|
|
98
|
-
return
|
|
58
|
+
if (typeof ImageBitmap !== "undefined" && value instanceof ImageBitmap) {
|
|
59
|
+
return imageValueFromBitmap(value, value.width, value.height);
|
|
99
60
|
}
|
|
100
|
-
|
|
101
|
-
|
|
61
|
+
if (typeof value === "string" && value.startsWith("data:")) {
|
|
62
|
+
if (typeof createImageBitmap === "function" && typeof fetch === "function") {
|
|
63
|
+
const blob = await (await fetch(value)).blob();
|
|
64
|
+
const bitmap = await createImageBitmap(blob);
|
|
65
|
+
return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
|
|
66
|
+
}
|
|
67
|
+
if (typeof Buffer !== "undefined") {
|
|
68
|
+
return decodeDataUriToNodeImageValue(value);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
102
71
|
}
|
|
103
|
-
|
|
104
|
-
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
async function decodeDataUriToNodeImageValue(dataUri) {
|
|
75
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(dataUri);
|
|
76
|
+
if (!match)
|
|
77
|
+
return;
|
|
78
|
+
const mime = match[1] ?? "image/png";
|
|
79
|
+
const base64 = match[2] ?? "";
|
|
80
|
+
const buffer = Buffer.from(base64, "base64");
|
|
81
|
+
const format = /jpe?g/i.test(mime) ? "jpeg" : "png";
|
|
82
|
+
try {
|
|
83
|
+
const decoded = await getImageRasterCodec().decodeDataUri(dataUri);
|
|
84
|
+
return imageValueFromBuffer(buffer, format, decoded.width, decoded.height);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
throw new Error("normalizeToImageValue: failed to probe data URI dimensions", {
|
|
87
|
+
cause: err
|
|
88
|
+
});
|
|
105
89
|
}
|
|
106
|
-
|
|
107
|
-
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/media/imageCacheCodec.ts
|
|
93
|
+
function isImageValueWire(v) {
|
|
94
|
+
if (v === null || typeof v !== "object")
|
|
95
|
+
return false;
|
|
96
|
+
const o = v;
|
|
97
|
+
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";
|
|
98
|
+
}
|
|
99
|
+
function bytesToBase64(bytes) {
|
|
100
|
+
if (typeof Buffer !== "undefined") {
|
|
101
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
108
102
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
let bin = "";
|
|
104
|
+
for (let i = 0;i < bytes.length; i++)
|
|
105
|
+
bin += String.fromCharCode(bytes[i] ?? 0);
|
|
106
|
+
return btoa(bin);
|
|
107
|
+
}
|
|
108
|
+
function base64ToBytes(b64) {
|
|
109
|
+
if (typeof Buffer !== "undefined") {
|
|
110
|
+
const buf = Buffer.from(b64, "base64");
|
|
111
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
const bin = atob(b64);
|
|
114
|
+
const out = new Uint8Array(bin.length);
|
|
115
|
+
for (let i = 0;i < bin.length; i++)
|
|
116
|
+
out[i] = bin.charCodeAt(i);
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
async function browserToPngBase64(value) {
|
|
120
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
121
|
+
throw new Error("imageCacheCodec.serialize: BrowserImageValue requires OffscreenCanvas");
|
|
115
122
|
}
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
const off = new OffscreenCanvas(value.width, value.height);
|
|
124
|
+
const ctx = off.getContext("2d");
|
|
125
|
+
if (!ctx)
|
|
126
|
+
throw new Error("imageCacheCodec.serialize: could not acquire 2D context");
|
|
127
|
+
ctx.drawImage(value.bitmap, 0, 0);
|
|
128
|
+
const blob = await off.convertToBlob({ type: "image/png" });
|
|
129
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
130
|
+
return bytesToBase64(bytes);
|
|
131
|
+
}
|
|
132
|
+
async function wireToBrowserImageValue(wire) {
|
|
133
|
+
if (typeof createImageBitmap !== "function") {
|
|
134
|
+
throw new Error("imageCacheCodec.deserialize: browser path requires createImageBitmap");
|
|
118
135
|
}
|
|
119
|
-
|
|
136
|
+
const bytes = base64ToBytes(wire.base64);
|
|
137
|
+
if (wire.format === "raw-rgba") {
|
|
120
138
|
if (typeof ImageData === "undefined") {
|
|
121
|
-
throw new Error("
|
|
139
|
+
throw new Error("imageCacheCodec.deserialize: raw-rgba decode requires ImageData");
|
|
122
140
|
}
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (canvas.height !== this.bin.height)
|
|
128
|
-
canvas.height = this.bin.height;
|
|
129
|
-
const ctx = canvas.getContext("2d");
|
|
130
|
-
if (!ctx)
|
|
131
|
-
throw new Error("CpuImage.toCanvas could not acquire a 2D context");
|
|
132
|
-
ctx.putImageData(id, 0, 0);
|
|
133
|
-
}
|
|
134
|
-
async encode(format, _quality) {
|
|
135
|
-
const codec = getImageRasterCodec();
|
|
136
|
-
const dataUri = await codec.encodeDataUri(this.bin, FORMAT_TO_MIME[format]);
|
|
137
|
-
return dataUriToBytes(dataUri);
|
|
138
|
-
}
|
|
139
|
-
retain(_n = 1) {
|
|
140
|
-
return this;
|
|
141
|
-
}
|
|
142
|
-
release() {}
|
|
143
|
-
static fromImageBinary(bin, previewScale = 1) {
|
|
144
|
-
return new CpuImage(bin, previewScale);
|
|
141
|
+
const data = new Uint8ClampedArray(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
142
|
+
const imageData = new ImageData(data, wire.width, wire.height);
|
|
143
|
+
const bitmap2 = await createImageBitmap(imageData);
|
|
144
|
+
return { bitmap: bitmap2, width: wire.width, height: wire.height, previewScale: wire.previewScale };
|
|
145
145
|
}
|
|
146
|
+
const mime = wire.format === "jpeg" ? "image/jpeg" : "image/png";
|
|
147
|
+
const blob = new Blob([bytes.buffer], { type: mime });
|
|
148
|
+
const bitmap = await createImageBitmap(blob);
|
|
149
|
+
return { bitmap, width: wire.width, height: wire.height, previewScale: wire.previewScale };
|
|
146
150
|
}
|
|
147
|
-
registerGpuImageFactory("fromImageBinary", CpuImage.fromImageBinary);
|
|
148
|
-
|
|
149
|
-
// src/media/imageCacheCodec.ts
|
|
150
151
|
registerPortCodec("image", {
|
|
151
152
|
async serialize(value) {
|
|
152
|
-
if (typeof value
|
|
153
|
+
if (typeof value === "string")
|
|
153
154
|
return value;
|
|
155
|
+
if (isNodeImageValue(value)) {
|
|
156
|
+
return {
|
|
157
|
+
__imageValueWire: 1,
|
|
158
|
+
format: value.format,
|
|
159
|
+
base64: value.buffer.toString("base64"),
|
|
160
|
+
width: value.width,
|
|
161
|
+
height: value.height,
|
|
162
|
+
previewScale: value.previewScale
|
|
163
|
+
};
|
|
154
164
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
if (isBrowserImageValue(value)) {
|
|
166
|
+
const base64 = await browserToPngBase64(value);
|
|
167
|
+
return {
|
|
168
|
+
__imageValueWire: 1,
|
|
169
|
+
format: "png",
|
|
170
|
+
base64,
|
|
171
|
+
width: value.width,
|
|
172
|
+
height: value.height,
|
|
173
|
+
previewScale: value.previewScale
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
throw new Error("imageCacheCodec.serialize: value is not an ImageValue or string");
|
|
163
177
|
},
|
|
164
|
-
async deserialize(
|
|
165
|
-
if (
|
|
166
|
-
return
|
|
178
|
+
async deserialize(wire) {
|
|
179
|
+
if (typeof wire === "string")
|
|
180
|
+
return wire;
|
|
181
|
+
if (!isImageValueWire(wire)) {
|
|
182
|
+
throw new Error("imageCacheCodec.deserialize: input is not an ImageValueWire or string");
|
|
167
183
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
channels: cached.channels
|
|
173
|
-
});
|
|
184
|
+
if (typeof Buffer !== "undefined") {
|
|
185
|
+
return imageValueFromBuffer(Buffer.from(wire.base64, "base64"), wire.format, wire.width, wire.height, wire.previewScale);
|
|
186
|
+
}
|
|
187
|
+
return wireToBrowserImageValue(wire);
|
|
174
188
|
}
|
|
175
189
|
});
|
|
176
190
|
|
|
@@ -180,17 +194,17 @@ class Container {
|
|
|
180
194
|
factories = new Map;
|
|
181
195
|
singletons = new Set;
|
|
182
196
|
resolving = [];
|
|
183
|
-
register(token,
|
|
184
|
-
this.factories.set(token,
|
|
197
|
+
register(token, factory, singleton = true) {
|
|
198
|
+
this.factories.set(token, factory);
|
|
185
199
|
if (singleton) {
|
|
186
200
|
this.singletons.add(token);
|
|
187
201
|
}
|
|
188
202
|
}
|
|
189
|
-
registerIfAbsent(token,
|
|
203
|
+
registerIfAbsent(token, factory, singleton = true) {
|
|
190
204
|
if (this.factories.has(token) || this.services.has(token)) {
|
|
191
205
|
return;
|
|
192
206
|
}
|
|
193
|
-
this.register(token,
|
|
207
|
+
this.register(token, factory, singleton);
|
|
194
208
|
}
|
|
195
209
|
registerInstance(token, instance) {
|
|
196
210
|
this.services.set(token, instance);
|
|
@@ -200,8 +214,8 @@ class Container {
|
|
|
200
214
|
if (this.services.has(token)) {
|
|
201
215
|
return this.services.get(token);
|
|
202
216
|
}
|
|
203
|
-
const
|
|
204
|
-
if (!
|
|
217
|
+
const factory = this.factories.get(token);
|
|
218
|
+
if (!factory) {
|
|
205
219
|
throw new Error(`Service not registered: ${String(token)}`);
|
|
206
220
|
}
|
|
207
221
|
if (this.resolving.includes(token)) {
|
|
@@ -210,7 +224,7 @@ class Container {
|
|
|
210
224
|
}
|
|
211
225
|
this.resolving.push(token);
|
|
212
226
|
try {
|
|
213
|
-
const instance =
|
|
227
|
+
const instance = factory();
|
|
214
228
|
if (this.singletons.has(token)) {
|
|
215
229
|
this.services.set(token, instance);
|
|
216
230
|
}
|
|
@@ -259,8 +273,8 @@ class Container {
|
|
|
259
273
|
}
|
|
260
274
|
createChildContainer() {
|
|
261
275
|
const child = new Container;
|
|
262
|
-
this.factories.forEach((
|
|
263
|
-
child.factories.set(token,
|
|
276
|
+
this.factories.forEach((factory, token) => {
|
|
277
|
+
child.factories.set(token, factory);
|
|
264
278
|
if (this.singletons.has(token)) {
|
|
265
279
|
child.singletons.add(token);
|
|
266
280
|
}
|
|
@@ -275,11 +289,11 @@ class Container {
|
|
|
275
289
|
}
|
|
276
290
|
}
|
|
277
291
|
var GLOBAL_CONTAINER_KEY = Symbol.for("@workglow/util/di/globalContainer");
|
|
278
|
-
var
|
|
279
|
-
if (!
|
|
280
|
-
|
|
292
|
+
var _g2 = globalThis;
|
|
293
|
+
if (!_g2[GLOBAL_CONTAINER_KEY]) {
|
|
294
|
+
_g2[GLOBAL_CONTAINER_KEY] = new Container;
|
|
281
295
|
}
|
|
282
|
-
var globalContainer =
|
|
296
|
+
var globalContainer = _g2[GLOBAL_CONTAINER_KEY];
|
|
283
297
|
|
|
284
298
|
// src/di/ServiceRegistry.ts
|
|
285
299
|
function createServiceToken(id) {
|
|
@@ -291,11 +305,11 @@ class ServiceRegistry {
|
|
|
291
305
|
constructor(container = globalContainer) {
|
|
292
306
|
this.container = container;
|
|
293
307
|
}
|
|
294
|
-
register(token,
|
|
295
|
-
this.container.register(token.id,
|
|
308
|
+
register(token, factory, singleton = true) {
|
|
309
|
+
this.container.register(token.id, factory, singleton);
|
|
296
310
|
}
|
|
297
|
-
registerIfAbsent(token,
|
|
298
|
-
this.container.registerIfAbsent(token.id,
|
|
311
|
+
registerIfAbsent(token, factory, singleton = true) {
|
|
312
|
+
this.container.registerIfAbsent(token.id, factory, singleton);
|
|
299
313
|
}
|
|
300
314
|
registerInstance(token, instance) {
|
|
301
315
|
this.container.registerInstance(token.id, instance);
|
|
@@ -324,16 +338,17 @@ function registerInputResolver(formatPrefix, resolver) {
|
|
|
324
338
|
}
|
|
325
339
|
|
|
326
340
|
// src/media/imageHydrationResolver.ts
|
|
327
|
-
async function
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
341
|
+
async function resolveImage(id, _format, _registry) {
|
|
342
|
+
const normalized = await normalizeToImageValue(id);
|
|
343
|
+
if (normalized !== undefined)
|
|
344
|
+
return normalized;
|
|
345
|
+
if (typeof id === "string") {
|
|
346
|
+
const preview = id.length > 32 ? `${id.slice(0, 32)}...` : id;
|
|
347
|
+
throw new Error(`format:"image" resolver received an unsupported string "${preview}". ` + `Only data: URIs are handled. Register a sub-resolver for other schemes.`);
|
|
332
348
|
}
|
|
333
|
-
|
|
334
|
-
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).`);
|
|
349
|
+
return id;
|
|
335
350
|
}
|
|
336
|
-
registerInputResolver("image",
|
|
351
|
+
registerInputResolver("image", resolveImage);
|
|
337
352
|
|
|
338
353
|
// src/media/color.ts
|
|
339
354
|
var HEX_PATTERN = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
@@ -443,8 +458,153 @@ function resolveColor(value) {
|
|
|
443
458
|
a: value.a ?? 255
|
|
444
459
|
};
|
|
445
460
|
}
|
|
461
|
+
// src/media/cpuImage.ts
|
|
462
|
+
var FORMAT_TO_MIME = {
|
|
463
|
+
png: "image/png",
|
|
464
|
+
jpeg: "image/jpeg",
|
|
465
|
+
webp: "image/webp"
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
class CpuImage {
|
|
469
|
+
bin;
|
|
470
|
+
backend = "cpu";
|
|
471
|
+
constructor(bin) {
|
|
472
|
+
this.bin = bin;
|
|
473
|
+
}
|
|
474
|
+
get width() {
|
|
475
|
+
if (!this.bin)
|
|
476
|
+
throw new Error("CpuImage.width on a disposed image");
|
|
477
|
+
return this.bin.width;
|
|
478
|
+
}
|
|
479
|
+
get height() {
|
|
480
|
+
if (!this.bin)
|
|
481
|
+
throw new Error("CpuImage.height on a disposed image");
|
|
482
|
+
return this.bin.height;
|
|
483
|
+
}
|
|
484
|
+
get channels() {
|
|
485
|
+
if (!this.bin)
|
|
486
|
+
throw new Error("CpuImage.channels on a disposed image");
|
|
487
|
+
return this.bin.channels;
|
|
488
|
+
}
|
|
489
|
+
getBinary() {
|
|
490
|
+
if (!this.bin)
|
|
491
|
+
throw new Error("CpuImage.getBinary on a disposed image");
|
|
492
|
+
return this.bin;
|
|
493
|
+
}
|
|
494
|
+
static async from(value) {
|
|
495
|
+
if (isBrowserImageValue(value)) {
|
|
496
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
497
|
+
throw new Error("CpuImage.from(BrowserImageValue) requires OffscreenCanvas");
|
|
498
|
+
}
|
|
499
|
+
const off = new OffscreenCanvas(value.width, value.height);
|
|
500
|
+
const ctx = off.getContext("2d");
|
|
501
|
+
if (!ctx)
|
|
502
|
+
throw new Error("CpuImage.from: could not acquire 2D context");
|
|
503
|
+
ctx.drawImage(value.bitmap, 0, 0);
|
|
504
|
+
const id = ctx.getImageData(0, 0, value.width, value.height);
|
|
505
|
+
return new CpuImage({ data: id.data, width: value.width, height: value.height, channels: 4 });
|
|
506
|
+
}
|
|
507
|
+
if (isNodeImageValue(value)) {
|
|
508
|
+
const bin = await decodeNodeImageValue(value);
|
|
509
|
+
return new CpuImage(bin);
|
|
510
|
+
}
|
|
511
|
+
throw new Error("CpuImage.from: unrecognized ImageValue shape");
|
|
512
|
+
}
|
|
513
|
+
static fromRaw(bin) {
|
|
514
|
+
return new CpuImage(bin);
|
|
515
|
+
}
|
|
516
|
+
async toImageValue(previewScale) {
|
|
517
|
+
if (!this.bin)
|
|
518
|
+
throw new Error("CpuImage.toImageValue on a disposed image");
|
|
519
|
+
if (typeof OffscreenCanvas !== "undefined" && typeof createImageBitmap === "function") {
|
|
520
|
+
const off = new OffscreenCanvas(this.bin.width, this.bin.height);
|
|
521
|
+
const ctx = off.getContext("2d");
|
|
522
|
+
if (!ctx)
|
|
523
|
+
throw new Error("CpuImage.toImageValue could not acquire a 2D context");
|
|
524
|
+
const rgba2 = expandToRgba(this.bin);
|
|
525
|
+
ctx.putImageData(new ImageData(new Uint8ClampedArray(rgba2.buffer, rgba2.byteOffset, rgba2.byteLength), this.bin.width, this.bin.height), 0, 0);
|
|
526
|
+
const bitmap = await createImageBitmap(off);
|
|
527
|
+
const out2 = {
|
|
528
|
+
bitmap,
|
|
529
|
+
width: this.bin.width,
|
|
530
|
+
height: this.bin.height,
|
|
531
|
+
previewScale
|
|
532
|
+
};
|
|
533
|
+
this.bin = null;
|
|
534
|
+
return out2;
|
|
535
|
+
}
|
|
536
|
+
const rgba = expandToRgba(this.bin);
|
|
537
|
+
const buffer = Buffer.from(rgba.buffer, rgba.byteOffset, rgba.byteLength);
|
|
538
|
+
const out = {
|
|
539
|
+
buffer,
|
|
540
|
+
format: "raw-rgba",
|
|
541
|
+
width: this.bin.width,
|
|
542
|
+
height: this.bin.height,
|
|
543
|
+
previewScale
|
|
544
|
+
};
|
|
545
|
+
this.bin = null;
|
|
546
|
+
return out;
|
|
547
|
+
}
|
|
548
|
+
async encode(format, _quality) {
|
|
549
|
+
if (!this.bin)
|
|
550
|
+
throw new Error("CpuImage.encode on a disposed image");
|
|
551
|
+
const codec = getImageRasterCodec();
|
|
552
|
+
const dataUri = await codec.encodeDataUri(this.bin, FORMAT_TO_MIME[format]);
|
|
553
|
+
return dataUriToBytes(dataUri);
|
|
554
|
+
}
|
|
555
|
+
dispose() {
|
|
556
|
+
this.bin = null;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function expandToRgba(bin) {
|
|
560
|
+
if (bin.channels === 4)
|
|
561
|
+
return bin.data;
|
|
562
|
+
const px = bin.width * bin.height;
|
|
563
|
+
const out = new Uint8ClampedArray(px * 4);
|
|
564
|
+
if (bin.channels === 3) {
|
|
565
|
+
for (let i = 0;i < px; i++) {
|
|
566
|
+
out[i * 4 + 0] = bin.data[i * 3 + 0] ?? 0;
|
|
567
|
+
out[i * 4 + 1] = bin.data[i * 3 + 1] ?? 0;
|
|
568
|
+
out[i * 4 + 2] = bin.data[i * 3 + 2] ?? 0;
|
|
569
|
+
out[i * 4 + 3] = 255;
|
|
570
|
+
}
|
|
571
|
+
} else if (bin.channels === 1) {
|
|
572
|
+
for (let i = 0;i < px; i++) {
|
|
573
|
+
const g = bin.data[i] ?? 0;
|
|
574
|
+
out[i * 4 + 0] = g;
|
|
575
|
+
out[i * 4 + 1] = g;
|
|
576
|
+
out[i * 4 + 2] = g;
|
|
577
|
+
out[i * 4 + 3] = 255;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return out;
|
|
581
|
+
}
|
|
582
|
+
function dataUriToBytes(dataUri) {
|
|
583
|
+
const comma = dataUri.indexOf(",");
|
|
584
|
+
const b64 = dataUri.slice(comma + 1);
|
|
585
|
+
const bin = atob(b64);
|
|
586
|
+
const bytes = new Uint8Array(bin.length);
|
|
587
|
+
for (let i = 0;i < bin.length; i++)
|
|
588
|
+
bytes[i] = bin.charCodeAt(i);
|
|
589
|
+
return bytes;
|
|
590
|
+
}
|
|
591
|
+
async function decodeNodeImageValue(value) {
|
|
592
|
+
if (value.format === "raw-rgba") {
|
|
593
|
+
const data = new Uint8ClampedArray(value.buffer.buffer, value.buffer.byteOffset, value.buffer.byteLength);
|
|
594
|
+
return { data, width: value.width, height: value.height, channels: 4 };
|
|
595
|
+
}
|
|
596
|
+
const codec = getImageRasterCodec();
|
|
597
|
+
const dataUri = `data:image/${value.format};base64,${value.buffer.toString("base64")}`;
|
|
598
|
+
const decoded = await codec.decodeDataUri(dataUri);
|
|
599
|
+
return {
|
|
600
|
+
data: decoded.data,
|
|
601
|
+
width: decoded.width,
|
|
602
|
+
height: decoded.height,
|
|
603
|
+
channels: decoded.channels
|
|
604
|
+
};
|
|
605
|
+
}
|
|
446
606
|
// src/media/encode.ts
|
|
447
|
-
async function
|
|
607
|
+
async function rawPixelBufferToBytes(bin, mimeType) {
|
|
448
608
|
const dataUri = await getImageRasterCodec().encodeDataUri(bin, mimeType);
|
|
449
609
|
const b64 = dataUri.slice(dataUri.indexOf(",") + 1);
|
|
450
610
|
const decoded = atob(b64);
|
|
@@ -453,28 +613,21 @@ async function encodeImageBinaryBytes(bin, mimeType) {
|
|
|
453
613
|
bytes[i] = decoded.charCodeAt(i);
|
|
454
614
|
return bytes;
|
|
455
615
|
}
|
|
456
|
-
async function
|
|
457
|
-
return encodeImageBinaryBytes(bin, "image/png");
|
|
458
|
-
}
|
|
459
|
-
async function imageBinaryToBase64Png(bin) {
|
|
460
|
-
const dataUri = await getImageRasterCodec().encodeDataUri(bin, "image/png");
|
|
461
|
-
return dataUri.slice(dataUri.indexOf(",") + 1);
|
|
462
|
-
}
|
|
463
|
-
async function imageBinaryToDataUri(bin, mimeType = "image/png") {
|
|
616
|
+
async function rawPixelBufferToDataUri(bin, mimeType = "image/png") {
|
|
464
617
|
return getImageRasterCodec().encodeDataUri(bin, mimeType);
|
|
465
618
|
}
|
|
466
|
-
async function
|
|
467
|
-
const bytes = await
|
|
619
|
+
async function rawPixelBufferToBlob(bin, mimeType = "image/png") {
|
|
620
|
+
const bytes = await rawPixelBufferToBytes(bin, mimeType);
|
|
468
621
|
return new Blob([bytes.buffer], { type: mimeType });
|
|
469
622
|
}
|
|
470
623
|
// src/media/filterRegistry.ts
|
|
471
624
|
var GLOBAL_REGISTRY_KEY = Symbol.for("@workglow/util/media/filterRegistry");
|
|
472
|
-
var
|
|
625
|
+
var _g3 = globalThis;
|
|
473
626
|
function getRegistry() {
|
|
474
|
-
let reg =
|
|
627
|
+
let reg = _g3[GLOBAL_REGISTRY_KEY];
|
|
475
628
|
if (!reg) {
|
|
476
629
|
reg = new Map;
|
|
477
|
-
|
|
630
|
+
_g3[GLOBAL_REGISTRY_KEY] = reg;
|
|
478
631
|
}
|
|
479
632
|
return reg;
|
|
480
633
|
}
|
|
@@ -495,28 +648,42 @@ function hasFilterOp(backend, filter) {
|
|
|
495
648
|
function _resetFilterRegistryForTests() {
|
|
496
649
|
getRegistry().clear();
|
|
497
650
|
}
|
|
498
|
-
// src/media/
|
|
499
|
-
|
|
651
|
+
// src/media/gpuImage.ts
|
|
652
|
+
var GLOBAL_FACTORY_KEY = Symbol.for("@workglow/util/media/gpuImageFactory");
|
|
653
|
+
var _g4 = globalThis;
|
|
654
|
+
if (!_g4[GLOBAL_FACTORY_KEY]) {
|
|
655
|
+
_g4[GLOBAL_FACTORY_KEY] = {};
|
|
656
|
+
}
|
|
657
|
+
var factory = _g4[GLOBAL_FACTORY_KEY];
|
|
658
|
+
function registerGpuImageFactory(key2, fn) {
|
|
659
|
+
factory[key2] = fn;
|
|
660
|
+
}
|
|
661
|
+
function getGpuImageFactory(key2) {
|
|
662
|
+
const fn = factory[key2];
|
|
663
|
+
return typeof fn === "function" ? fn : undefined;
|
|
664
|
+
}
|
|
665
|
+
var GpuImage = new Proxy({}, {
|
|
666
|
+
get(_t, prop) {
|
|
667
|
+
if (typeof prop !== "string" || prop === "then")
|
|
668
|
+
return;
|
|
669
|
+
const fn = factory[prop];
|
|
670
|
+
if (typeof fn !== "function") {
|
|
671
|
+
throw new Error(`GpuImage.${prop} is not registered. Import the platform entry point.`);
|
|
672
|
+
}
|
|
673
|
+
return fn;
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
// src/media/imageValueSchema.ts
|
|
677
|
+
function ImageValueSchema(annotations = {}) {
|
|
500
678
|
return {
|
|
501
679
|
type: ["string", "object"],
|
|
502
680
|
properties: {},
|
|
503
681
|
title: "Image",
|
|
504
|
-
description: "Image (hydrated to
|
|
682
|
+
description: "Image (hydrated to ImageValue at task entry)",
|
|
505
683
|
...annotations,
|
|
506
684
|
format: "image"
|
|
507
685
|
};
|
|
508
686
|
}
|
|
509
|
-
// src/media/imageTypes.ts
|
|
510
|
-
function parseDataUri(dataUri) {
|
|
511
|
-
const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);
|
|
512
|
-
if (!match) {
|
|
513
|
-
throw new Error("Invalid base64 data URI");
|
|
514
|
-
}
|
|
515
|
-
return {
|
|
516
|
-
mimeType: match[1],
|
|
517
|
-
base64: match[2]
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
687
|
// src/media/MediaRawImage.ts
|
|
521
688
|
class MediaRawImage {
|
|
522
689
|
data;
|
|
@@ -559,9 +726,7 @@ function setPreviewBudget(px) {
|
|
|
559
726
|
}
|
|
560
727
|
_g5[GLOBAL_BUDGET_KEY] = Math.floor(px);
|
|
561
728
|
}
|
|
562
|
-
function previewSource(image) {
|
|
563
|
-
if (image.backend !== "webgpu")
|
|
564
|
-
return image;
|
|
729
|
+
async function previewSource(image) {
|
|
565
730
|
const budget = getPreviewBudget();
|
|
566
731
|
const long = Math.max(image.width, image.height);
|
|
567
732
|
if (long <= budget)
|
|
@@ -570,9 +735,14 @@ function previewSource(image) {
|
|
|
570
735
|
const resize = getPreviewResizeFn();
|
|
571
736
|
if (!resize)
|
|
572
737
|
return image;
|
|
573
|
-
const
|
|
574
|
-
const
|
|
575
|
-
|
|
738
|
+
const targetW = Math.max(1, Math.round(image.width * ratio));
|
|
739
|
+
const targetH = Math.max(1, Math.round(image.height * ratio));
|
|
740
|
+
const result = await resize(image, targetW, targetH);
|
|
741
|
+
const composedScale = image.previewScale * ratio;
|
|
742
|
+
return {
|
|
743
|
+
...result,
|
|
744
|
+
previewScale: composedScale
|
|
745
|
+
};
|
|
576
746
|
}
|
|
577
747
|
// src/media/shaderRegistry.browser.ts
|
|
578
748
|
var VERTEX_PRELUDE = `
|
|
@@ -687,12 +857,17 @@ function resetTexturePoolForTests() {
|
|
|
687
857
|
singleton2?.pool.drain();
|
|
688
858
|
singleton2 = null;
|
|
689
859
|
}
|
|
690
|
-
// src/media/sharpImage.
|
|
860
|
+
// src/media/sharpImage.server.ts
|
|
691
861
|
var cachedSharp = null;
|
|
692
862
|
async function loadSharp() {
|
|
693
863
|
if (cachedSharp)
|
|
694
864
|
return cachedSharp;
|
|
695
|
-
|
|
865
|
+
let mod;
|
|
866
|
+
try {
|
|
867
|
+
mod = await import("sharp");
|
|
868
|
+
} catch {
|
|
869
|
+
throw new Error("Server-side image processing requires the optional 'sharp' package. Install it with: npm install sharp (or bun add sharp)");
|
|
870
|
+
}
|
|
696
871
|
cachedSharp = mod.default ?? mod;
|
|
697
872
|
return cachedSharp;
|
|
698
873
|
}
|
|
@@ -703,61 +878,69 @@ class SharpImage {
|
|
|
703
878
|
height;
|
|
704
879
|
channels;
|
|
705
880
|
backend = "sharp";
|
|
706
|
-
|
|
707
|
-
constructor(pipeline, width, height, channels, previewScale = 1) {
|
|
881
|
+
constructor(pipeline, width, height, channels) {
|
|
708
882
|
this.pipeline = pipeline;
|
|
709
883
|
this.width = width;
|
|
710
884
|
this.height = height;
|
|
711
885
|
this.channels = channels;
|
|
712
|
-
this._previewScale = previewScale;
|
|
713
886
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
static async fromImageBinary(bin, previewScale = 1) {
|
|
722
|
-
const sharp = await loadSharp();
|
|
723
|
-
const buf = Buffer.from(bin.data.buffer, bin.data.byteOffset, bin.data.byteLength);
|
|
724
|
-
const pipeline = sharp(buf, {
|
|
725
|
-
raw: { width: bin.width, height: bin.height, channels: bin.channels }
|
|
726
|
-
});
|
|
727
|
-
return new SharpImage(pipeline, bin.width, bin.height, bin.channels, previewScale);
|
|
728
|
-
}
|
|
729
|
-
static async fromBuffer(buf) {
|
|
887
|
+
static async from(value) {
|
|
888
|
+
if (isBrowserImageValue(value)) {
|
|
889
|
+
throw new Error("SharpImage.from: BrowserImageValue not supported in node runtime");
|
|
890
|
+
}
|
|
891
|
+
if (!isNodeImageValue(value)) {
|
|
892
|
+
throw new Error("SharpImage.from: unrecognized ImageValue shape");
|
|
893
|
+
}
|
|
730
894
|
const sharp = await loadSharp();
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
895
|
+
if (value.format === "raw-rgba") {
|
|
896
|
+
const pipeline2 = sharp(value.buffer, {
|
|
897
|
+
raw: { width: value.width, height: value.height, channels: 4 }
|
|
898
|
+
});
|
|
899
|
+
return new SharpImage(pipeline2, value.width, value.height, 4);
|
|
735
900
|
}
|
|
736
|
-
|
|
901
|
+
const pipeline = sharp(value.buffer);
|
|
902
|
+
const meta = await pipeline.clone().metadata();
|
|
903
|
+
const channels = meta.channels ?? 4;
|
|
904
|
+
return new SharpImage(pipeline, value.width, value.height, channels);
|
|
737
905
|
}
|
|
738
906
|
apply(op, outSize) {
|
|
907
|
+
if (!this.pipeline)
|
|
908
|
+
throw new Error("SharpImage.apply on a disposed image");
|
|
739
909
|
const next = op(this.pipeline.clone());
|
|
740
|
-
return new SharpImage(next, outSize?.width ?? this.width, outSize?.height ?? this.height, outSize?.channels ?? this.channels
|
|
910
|
+
return new SharpImage(next, outSize?.width ?? this.width, outSize?.height ?? this.height, outSize?.channels ?? this.channels);
|
|
741
911
|
}
|
|
742
|
-
async
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
912
|
+
async toBuffer(format) {
|
|
913
|
+
if (!this.pipeline)
|
|
914
|
+
throw new Error("SharpImage.toBuffer on a disposed image");
|
|
915
|
+
const p = this.pipeline.clone();
|
|
916
|
+
if (format === "raw-rgba") {
|
|
917
|
+
const result = await p.raw().toBuffer({ resolveWithObject: true });
|
|
918
|
+
if (!isObjectResult(result))
|
|
919
|
+
throw new Error("SharpImage.toBuffer: expected resolveWithObject result");
|
|
920
|
+
return result.data;
|
|
746
921
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
return {
|
|
751
|
-
data: out,
|
|
752
|
-
width: info.width,
|
|
753
|
-
height: info.height,
|
|
754
|
-
channels: info.channels
|
|
755
|
-
};
|
|
922
|
+
if (format === "png")
|
|
923
|
+
return await p.png().toBuffer();
|
|
924
|
+
return await p.jpeg().toBuffer();
|
|
756
925
|
}
|
|
757
|
-
async
|
|
758
|
-
|
|
926
|
+
async toImageValue(previewScale) {
|
|
927
|
+
try {
|
|
928
|
+
const buffer = await this.toBuffer("png");
|
|
929
|
+
const out = {
|
|
930
|
+
buffer,
|
|
931
|
+
format: "png",
|
|
932
|
+
width: this.width,
|
|
933
|
+
height: this.height,
|
|
934
|
+
previewScale
|
|
935
|
+
};
|
|
936
|
+
return out;
|
|
937
|
+
} finally {
|
|
938
|
+
this.dispose();
|
|
939
|
+
}
|
|
759
940
|
}
|
|
760
941
|
async encode(format, quality) {
|
|
942
|
+
if (!this.pipeline)
|
|
943
|
+
throw new Error("SharpImage.encode on a disposed image");
|
|
761
944
|
const p = this.pipeline.clone();
|
|
762
945
|
let result;
|
|
763
946
|
if (format === "png")
|
|
@@ -769,28 +952,64 @@ class SharpImage {
|
|
|
769
952
|
const buf = result;
|
|
770
953
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
771
954
|
}
|
|
772
|
-
|
|
773
|
-
|
|
955
|
+
dispose() {
|
|
956
|
+
this.pipeline = null;
|
|
774
957
|
}
|
|
775
|
-
release() {}
|
|
776
958
|
}
|
|
777
959
|
function isObjectResult(r) {
|
|
778
960
|
return !!r && typeof r === "object" && "data" in r && "info" in r;
|
|
779
961
|
}
|
|
962
|
+
async function probeImageDimensions(buffer) {
|
|
963
|
+
const sharp = await loadSharp();
|
|
964
|
+
const meta = await sharp(buffer).metadata();
|
|
965
|
+
if (typeof meta.width !== "number" || typeof meta.height !== "number") {
|
|
966
|
+
throw new Error("probeImageDimensions: sharp could not read image dimensions");
|
|
967
|
+
}
|
|
968
|
+
return { width: meta.width, height: meta.height, channels: meta.channels };
|
|
969
|
+
}
|
|
970
|
+
async function decodeBufferToRaw(buffer, options) {
|
|
971
|
+
const sharp = await loadSharp();
|
|
972
|
+
const sharpOpts = {};
|
|
973
|
+
if (options?.limitInputPixels !== undefined)
|
|
974
|
+
sharpOpts.limitInputPixels = options.limitInputPixels;
|
|
975
|
+
if (options?.sequentialRead !== undefined)
|
|
976
|
+
sharpOpts.sequentialRead = options.sequentialRead;
|
|
977
|
+
let pipeline = sharp(buffer, sharpOpts);
|
|
978
|
+
if (options?.ensureAlpha)
|
|
979
|
+
pipeline = pipeline.ensureAlpha();
|
|
980
|
+
const result = await pipeline.raw().toBuffer({ resolveWithObject: true });
|
|
981
|
+
if (!isObjectResult(result))
|
|
982
|
+
throw new Error("decodeBufferToRaw: expected resolveWithObject result");
|
|
983
|
+
return {
|
|
984
|
+
data: result.data,
|
|
985
|
+
width: result.info.width,
|
|
986
|
+
height: result.info.height,
|
|
987
|
+
channels: result.info.channels
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
async function encodeRawPixels(raw, options) {
|
|
991
|
+
const sharp = await loadSharp();
|
|
992
|
+
const inputBuffer = raw.data instanceof Uint8ClampedArray ? Buffer.from(raw.data.buffer, raw.data.byteOffset, raw.data.byteLength) : raw.data;
|
|
993
|
+
const pipeline = sharp(inputBuffer, {
|
|
994
|
+
raw: { width: raw.width, height: raw.height, channels: raw.channels }
|
|
995
|
+
});
|
|
996
|
+
let encoded;
|
|
997
|
+
if (options.format === "png") {
|
|
998
|
+
encoded = await pipeline.png({ compressionLevel: options.compressionLevel }).toBuffer();
|
|
999
|
+
} else if (options.format === "jpeg") {
|
|
1000
|
+
encoded = await pipeline.jpeg({ quality: options.quality, mozjpeg: options.mozjpeg }).toBuffer();
|
|
1001
|
+
} else {
|
|
1002
|
+
encoded = await pipeline.webp({ quality: options.quality }).toBuffer();
|
|
1003
|
+
}
|
|
1004
|
+
return encoded;
|
|
1005
|
+
}
|
|
1006
|
+
registerGpuImageFactory("from", SharpImage.from.bind(SharpImage));
|
|
780
1007
|
// src/media-node.ts
|
|
781
1008
|
async function getGpuDevice() {
|
|
782
1009
|
return null;
|
|
783
1010
|
}
|
|
784
1011
|
function resetGpuDeviceForTests() {}
|
|
785
|
-
registerGpuImageFactory("
|
|
786
|
-
registerGpuImageFactory("fromDataUri", async (dataUri) => {
|
|
787
|
-
const bin = await getImageRasterCodec().decodeDataUri(dataUri);
|
|
788
|
-
return SharpImage.fromImageBinary(bin);
|
|
789
|
-
});
|
|
790
|
-
registerGpuImageFactory("fromBlob", async (blob) => {
|
|
791
|
-
const buf = Buffer.from(await blob.arrayBuffer());
|
|
792
|
-
return SharpImage.fromBuffer(buf);
|
|
793
|
-
});
|
|
1012
|
+
registerGpuImageFactory("from", (value) => SharpImage.from(value));
|
|
794
1013
|
export {
|
|
795
1014
|
toHexColor,
|
|
796
1015
|
setPreviewBudget,
|
|
@@ -801,15 +1020,20 @@ export {
|
|
|
801
1020
|
registerImageRasterCodec,
|
|
802
1021
|
registerGpuImageFactory,
|
|
803
1022
|
registerFilterOp,
|
|
1023
|
+
rawPixelBufferToDataUri,
|
|
1024
|
+
rawPixelBufferToBlob,
|
|
1025
|
+
probeImageDimensions,
|
|
804
1026
|
previewSource,
|
|
805
1027
|
parseHexColor,
|
|
806
|
-
|
|
1028
|
+
normalizeToImageValue,
|
|
1029
|
+
isNodeImageValue,
|
|
807
1030
|
isMediaRawImageShape,
|
|
1031
|
+
isImageValue,
|
|
808
1032
|
isHexColor,
|
|
809
1033
|
isColorObject,
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1034
|
+
isBrowserImageValue,
|
|
1035
|
+
imageValueFromBuffer,
|
|
1036
|
+
imageValueFromBitmap,
|
|
813
1037
|
hasFilterOp,
|
|
814
1038
|
getTexturePool,
|
|
815
1039
|
getShaderCache,
|
|
@@ -817,7 +1041,8 @@ export {
|
|
|
817
1041
|
getImageRasterCodec,
|
|
818
1042
|
getGpuImageFactory,
|
|
819
1043
|
getGpuDevice,
|
|
820
|
-
|
|
1044
|
+
encodeRawPixels,
|
|
1045
|
+
decodeBufferToRaw,
|
|
821
1046
|
createTexturePool,
|
|
822
1047
|
createShaderCache,
|
|
823
1048
|
applyFilter,
|
|
@@ -826,9 +1051,9 @@ export {
|
|
|
826
1051
|
SharpImage,
|
|
827
1052
|
PASSTHROUGH_SHADER_SRC,
|
|
828
1053
|
MediaRawImage,
|
|
829
|
-
|
|
1054
|
+
ImageValueSchema,
|
|
830
1055
|
GpuImage as GpuImageFactory,
|
|
831
1056
|
CpuImage
|
|
832
1057
|
};
|
|
833
1058
|
|
|
834
|
-
//# debugId=
|
|
1059
|
+
//# debugId=49C9406160EA2AA164756E2164756E21
|