@poe-platform/safe-bash 0.1.835 → 0.1.837
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/image-ast/browser/codecs/gif-output-parts.d.ts +2 -0
- package/dist/image-ast/browser/codecs/gif-storage.d.ts +1 -1
- package/dist/image-ast/codecs/gif-output-parts.d.ts +2 -0
- package/dist/image-ast/codecs/gif-storage.d.ts +1 -1
- package/dist/image-ast/index.js +62 -1
- package/dist/pdf-ast/image.js +1 -1
- package/dist/pdf-ast/index.js +1 -1
- package/dist/pdf-ast/render/raster.d.ts +4 -3
- package/dist/pdf-ast/render/retained-page-pixels.d.ts +3 -2
- package/dist/safe-bash/command-chunks/{chunk-YHRESVJ7.js → chunk-4BSD2RGK.js} +132 -70
- package/dist/safe-bash/command-chunks/{chunk-GQQUZGIZ.js → chunk-FH5VMAPS.js} +99287 -51054
- package/dist/safe-bash/command-chunks/{chunk-THJIIMGT.js → chunk-RSFKQE2U.js} +1 -1
- package/dist/safe-bash-command-ffmpeg/index.js +33 -21
- package/dist/safe-bash-command-ffprobe/index.js +2 -2
- package/dist/safe-bash-command-ffprobe/media.js +2 -2
- package/dist/safe-bash-command-imagemagick/index.js +345 -158
- package/package.json +2 -2
|
@@ -1,5 +1,215 @@
|
|
|
1
1
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
|
2
2
|
|
|
3
|
+
// packages/safe-bash-command-imagemagick/src/connected-components.ts
|
|
4
|
+
import { yieldTurn as yieldTurn2 } from "../safe-bash-contracts/yield.js";
|
|
5
|
+
|
|
6
|
+
// packages/safe-bash-command-imagemagick/src/raster-backing.ts
|
|
7
|
+
import { yieldTurn } from "../safe-bash-contracts/yield.js";
|
|
8
|
+
var RasterBackingCache = class {
|
|
9
|
+
constructor(storage, signal) {
|
|
10
|
+
this.storage = storage;
|
|
11
|
+
this.signal = signal;
|
|
12
|
+
}
|
|
13
|
+
storage;
|
|
14
|
+
signal;
|
|
15
|
+
pages = /* @__PURE__ */ new Map();
|
|
16
|
+
work = 0;
|
|
17
|
+
async allocate(length) {
|
|
18
|
+
const region = { position: this.storage.allocate(length), length }, zero = new Uint8Array(Math.min(4096, length));
|
|
19
|
+
for (let offset = 0; offset < length; offset += zero.length) {
|
|
20
|
+
if (offset % 65536 === 0) await yieldTurn(this.signal);
|
|
21
|
+
await this.storage.write(region.position + offset, zero.subarray(0, Math.min(zero.length, length - offset)), { signal: this.signal });
|
|
22
|
+
}
|
|
23
|
+
return region;
|
|
24
|
+
}
|
|
25
|
+
async page(region, offset) {
|
|
26
|
+
this.signal.throwIfAborted();
|
|
27
|
+
if (++this.work % 16384 === 0) await yieldTurn(this.signal);
|
|
28
|
+
const start = Math.floor(offset / 4096) * 4096, key = region.position + ":" + start;
|
|
29
|
+
let page = this.pages.get(key);
|
|
30
|
+
if (page) {
|
|
31
|
+
this.pages.delete(key);
|
|
32
|
+
this.pages.set(key, page);
|
|
33
|
+
return page;
|
|
34
|
+
}
|
|
35
|
+
if (this.pages.size === 32) {
|
|
36
|
+
const oldest = this.pages.entries().next().value;
|
|
37
|
+
if (oldest[1].dirty) await this.storage.write(oldest[1].position, oldest[1].bytes, { signal: this.signal });
|
|
38
|
+
this.pages.delete(oldest[0]);
|
|
39
|
+
}
|
|
40
|
+
const length = Math.min(4096, region.length - start), borrowed = await this.storage.read(region.position + start, length, { signal: this.signal });
|
|
41
|
+
if (borrowed.length !== length) throw new Error("Truncated raster backing");
|
|
42
|
+
const bytes = new Uint8Array(borrowed);
|
|
43
|
+
page = { position: region.position + start, bytes, view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), dirty: false };
|
|
44
|
+
this.pages.set(key, page);
|
|
45
|
+
return page;
|
|
46
|
+
}
|
|
47
|
+
async byte(region, offset) {
|
|
48
|
+
return (await this.page(region, offset)).bytes[offset % 4096];
|
|
49
|
+
}
|
|
50
|
+
async mark(region, offset) {
|
|
51
|
+
const page = await this.page(region, offset);
|
|
52
|
+
page.bytes[offset % 4096] = 1;
|
|
53
|
+
page.dirty = true;
|
|
54
|
+
}
|
|
55
|
+
async uint32(region, offset) {
|
|
56
|
+
return (await this.page(region, offset)).view.getUint32(offset % 4096, true);
|
|
57
|
+
}
|
|
58
|
+
async setUint32(region, offset, value) {
|
|
59
|
+
const page = await this.page(region, offset);
|
|
60
|
+
page.view.setUint32(offset % 4096, value, true);
|
|
61
|
+
page.dirty = true;
|
|
62
|
+
}
|
|
63
|
+
async float32(region, offset) {
|
|
64
|
+
return (await this.page(region, offset)).view.getFloat32(offset % 4096, true);
|
|
65
|
+
}
|
|
66
|
+
async setFloat32(region, offset, value) {
|
|
67
|
+
const page = await this.page(region, offset);
|
|
68
|
+
page.view.setFloat32(offset % 4096, value, true);
|
|
69
|
+
page.dirty = true;
|
|
70
|
+
}
|
|
71
|
+
async flush() {
|
|
72
|
+
for (const page of this.pages.values()) {
|
|
73
|
+
this.signal.throwIfAborted();
|
|
74
|
+
if (page.dirty) {
|
|
75
|
+
await this.storage.write(page.position, page.bytes, { signal: this.signal });
|
|
76
|
+
page.dirty = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// packages/safe-bash-command-imagemagick/src/connected-components.ts
|
|
83
|
+
function* labelSteps(width, height, connectivity) {
|
|
84
|
+
const components = [];
|
|
85
|
+
for (let seed = 0; seed < width * height; seed++) {
|
|
86
|
+
if (seed % 1024 === 0) yield;
|
|
87
|
+
if (yield { region: "labels", index: seed }) continue;
|
|
88
|
+
if (components.length === 65536) throw new Error("connected-components: too many objects (maximum 65536)");
|
|
89
|
+
const id = components.length, color = yield { region: "pixels", index: seed };
|
|
90
|
+
const component = { id, area: 0, x: 0, y: 0, left: width, top: height, right: 0, bottom: 0, color: [0, 0, 0, 0] };
|
|
91
|
+
let head = 0, tail = 1;
|
|
92
|
+
yield { region: "labels", index: seed, value: id + 1 };
|
|
93
|
+
yield { region: "queue", index: 0, value: seed };
|
|
94
|
+
while (head < tail) {
|
|
95
|
+
if (head % 1024 === 0) yield;
|
|
96
|
+
const current = yield { region: "queue", index: head++ }, x = current % width, y = Math.floor(current / width);
|
|
97
|
+
const pixel = yield { region: "pixels", index: current };
|
|
98
|
+
component.area++;
|
|
99
|
+
component.x += x;
|
|
100
|
+
component.y += y;
|
|
101
|
+
component.left = Math.min(component.left, x);
|
|
102
|
+
component.right = Math.max(component.right, x);
|
|
103
|
+
component.top = Math.min(component.top, y);
|
|
104
|
+
component.bottom = Math.max(component.bottom, y);
|
|
105
|
+
for (let channel = 0; channel < 4; channel++) component.color[channel] += pixel >>> channel * 8 & 255;
|
|
106
|
+
for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
|
|
107
|
+
if (!dx && !dy || connectivity === 4 && dx && dy || x + dx < 0 || x + dx >= width || y + dy < 0 || y + dy >= height) continue;
|
|
108
|
+
const next = (y + dy) * width + x + dx;
|
|
109
|
+
if (yield { region: "labels", index: next }) continue;
|
|
110
|
+
const neighbor = yield { region: "pixels", index: next };
|
|
111
|
+
if (neighbor !== color && (neighbor >>> 24 !== 0 || color >>> 24 !== 0)) continue;
|
|
112
|
+
yield { region: "labels", index: next, value: id + 1 };
|
|
113
|
+
yield { region: "queue", index: tail++, value: next };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
components.push(component);
|
|
117
|
+
}
|
|
118
|
+
return components;
|
|
119
|
+
}
|
|
120
|
+
function* reportSteps(components) {
|
|
121
|
+
let sorted = components.slice();
|
|
122
|
+
for (let span = 1; span < sorted.length; span *= 2) {
|
|
123
|
+
const next = [];
|
|
124
|
+
for (let start = 0; start < sorted.length; start += span * 2) {
|
|
125
|
+
let left = start, right = Math.min(start + span, sorted.length);
|
|
126
|
+
const middle = right, end = Math.min(start + span * 2, sorted.length);
|
|
127
|
+
while (left < middle || right < end) {
|
|
128
|
+
if (next.length % 1024 === 0) yield;
|
|
129
|
+
next.push(right === end || left < middle && sorted[left].area >= sorted[right].area ? sorted[left++] : sorted[right++]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
sorted = next;
|
|
133
|
+
}
|
|
134
|
+
let text = "Objects (id: bounding-box centroid area mean-color):\n";
|
|
135
|
+
for (const c of sorted) {
|
|
136
|
+
if (c.id % 1024 === 0) yield;
|
|
137
|
+
const channels = c.color.slice(0, 3).map((value) => Number((value / c.area).toPrecision(6)));
|
|
138
|
+
const color = c.color[3] < c.area * 255 ? `srgba(${channels.join(",")},${Number((c.color[3] / c.area / 255).toPrecision(6))})` : `srgb(${channels.join(",")})`;
|
|
139
|
+
text += ` ${c.id}: ${c.right - c.left + 1}x${c.bottom - c.top + 1}+${c.left}+${c.top} ${(c.x / c.area).toFixed(1)},${(c.y / c.area).toFixed(1)} ${c.area} ${color}
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
return text;
|
|
143
|
+
}
|
|
144
|
+
function* connectedComponentsSteps(image, connectivity, verbose) {
|
|
145
|
+
const count = image.width * image.height, labels = new Uint32Array(count), queue = new Uint32Array(count), pixels = new DataView(image.data.buffer, image.data.byteOffset, image.data.byteLength);
|
|
146
|
+
const steps = labelSteps(image.width, image.height, connectivity);
|
|
147
|
+
let next = steps.next();
|
|
148
|
+
while (!next.done) {
|
|
149
|
+
const request = next.value;
|
|
150
|
+
if (!request) {
|
|
151
|
+
yield;
|
|
152
|
+
next = steps.next(0);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const { region, index, value } = request;
|
|
156
|
+
if (region === "pixels") next = steps.next(pixels.getUint32(index * 4, true));
|
|
157
|
+
else {
|
|
158
|
+
const data2 = region === "labels" ? labels : queue;
|
|
159
|
+
if (value !== void 0) data2[index] = value;
|
|
160
|
+
next = steps.next(data2[index]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const text = verbose ? yield* reportSteps(next.value) : "", data = new Uint8Array(count * 4);
|
|
164
|
+
for (let i = 0; i < count; i++) {
|
|
165
|
+
if (i % 1024 === 0) yield;
|
|
166
|
+
const value = Math.round((labels[i] - 1) / 257);
|
|
167
|
+
data.set([value, value, value, 255], i * 4);
|
|
168
|
+
}
|
|
169
|
+
return { image: { ...image, data, hasAlpha: false, space: "srgb" }, text };
|
|
170
|
+
}
|
|
171
|
+
async function connectedComponentsStored(image, storage, connectivity, verbose, signal) {
|
|
172
|
+
const size = image.width * image.height * 4, cache = new RasterBackingCache(storage, signal);
|
|
173
|
+
const regions = { pixels: { position: image.position, length: size }, labels: await cache.allocate(size), queue: await cache.allocate(size) };
|
|
174
|
+
const steps = labelSteps(image.width, image.height, connectivity);
|
|
175
|
+
let next = steps.next();
|
|
176
|
+
while (!next.done) {
|
|
177
|
+
const request = next.value;
|
|
178
|
+
if (!request) {
|
|
179
|
+
await yieldTurn2(signal);
|
|
180
|
+
next = steps.next(0);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const region = regions[request.region], offset = request.index * 4;
|
|
184
|
+
if (request.value !== void 0) {
|
|
185
|
+
await cache.setUint32(region, offset, request.value);
|
|
186
|
+
next = steps.next(0);
|
|
187
|
+
} else next = steps.next(await cache.uint32(region, offset));
|
|
188
|
+
}
|
|
189
|
+
let text = "";
|
|
190
|
+
if (verbose) {
|
|
191
|
+
const report = reportSteps(next.value);
|
|
192
|
+
let part = report.next();
|
|
193
|
+
while (!part.done) {
|
|
194
|
+
await yieldTurn2(signal);
|
|
195
|
+
part = report.next();
|
|
196
|
+
}
|
|
197
|
+
text = part.value;
|
|
198
|
+
}
|
|
199
|
+
await cache.flush();
|
|
200
|
+
const position = storage.allocate(size);
|
|
201
|
+
for (let offset = 0; offset < size; offset += 4096) {
|
|
202
|
+
await yieldTurn2(signal);
|
|
203
|
+
const bytes = new Uint8Array(await storage.read(regions.labels.position + offset, Math.min(4096, size - offset), { signal })), view = new DataView(bytes.buffer);
|
|
204
|
+
for (let i = 0; i < bytes.length; i += 4) {
|
|
205
|
+
const value = Math.round((view.getUint32(i, true) - 1) / 257);
|
|
206
|
+
bytes.set([value, value, value, 255], i);
|
|
207
|
+
}
|
|
208
|
+
await storage.write(position + offset, bytes, { signal });
|
|
209
|
+
}
|
|
210
|
+
return { image: { ...image, position, hasAlpha: false, space: "srgb" }, text };
|
|
211
|
+
}
|
|
212
|
+
|
|
3
213
|
// packages/safe-bash-command-imagemagick/src/sequence-kernel.ts
|
|
4
214
|
var byte = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
5
215
|
function* clutPixelSteps(size, lut, mask) {
|
|
@@ -250,7 +460,7 @@ async function withImageInputs(input, stdinBytes, signal, run) {
|
|
|
250
460
|
|
|
251
461
|
// packages/safe-bash-command-imagemagick/src/text-output.ts
|
|
252
462
|
import { IntegerTable } from "@poe-platform/safe-fs/storage";
|
|
253
|
-
import { yieldTurn } from "../safe-bash-contracts/yield.js";
|
|
463
|
+
import { yieldTurn as yieldTurn3 } from "../safe-bash-contracts/yield.js";
|
|
254
464
|
var hex = (value) => value.toString(16).toUpperCase().padStart(2, "0");
|
|
255
465
|
function pixelEnumerationLine(x, y, r, g, b, a) {
|
|
256
466
|
return `${x},${y}: (${r},${g},${b},${a}) #${hex(r)}${hex(g)}${hex(b)}${a < 255 ? hex(a) : ""} srgba(${r},${g},${b},${(a / 255).toFixed(3)})`;
|
|
@@ -264,7 +474,7 @@ async function* storedPixelEnumeration(image, storage, signal) {
|
|
|
264
474
|
`;
|
|
265
475
|
const size = image.width * image.height * 4;
|
|
266
476
|
for (let start = 0; start < size; start += 16384) {
|
|
267
|
-
await
|
|
477
|
+
await yieldTurn3(signal);
|
|
268
478
|
const bytes = await storage.read(image.position + start, Math.min(16384, size - start));
|
|
269
479
|
for (let offset = 0; offset < bytes.length; offset += 4) {
|
|
270
480
|
const pixel = (start + offset) / 4;
|
|
@@ -276,7 +486,7 @@ async function* storedHistogram(image, storage, signal) {
|
|
|
276
486
|
const counts = new IntegerTable(storage, 512), order = new IntegerTable(storage, 128), size = image.width * image.height * 4;
|
|
277
487
|
let unique = 0;
|
|
278
488
|
for (let start = 0; start < size; start += 16384) {
|
|
279
|
-
await
|
|
489
|
+
await yieldTurn3(signal);
|
|
280
490
|
const bytes = await storage.read(image.position + start, Math.min(16384, size - start));
|
|
281
491
|
for (let offset = 0; offset < bytes.length; offset += 4) {
|
|
282
492
|
const key = BigInt((bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0), count = await counts.get(key);
|
|
@@ -285,7 +495,7 @@ async function* storedHistogram(image, storage, signal) {
|
|
|
285
495
|
}
|
|
286
496
|
}
|
|
287
497
|
for (let index = 0; index < unique; index++) {
|
|
288
|
-
if (index % 128 === 0) await
|
|
498
|
+
if (index % 128 === 0) await yieldTurn3(signal);
|
|
289
499
|
const key = await order.get(BigInt(index));
|
|
290
500
|
yield histogramLine(Number(key), Number(await counts.get(key))) + "\n";
|
|
291
501
|
}
|
|
@@ -327,7 +537,7 @@ async function* encodeText(parts, signal) {
|
|
|
327
537
|
|
|
328
538
|
// packages/safe-bash-command-imagemagick/src/stored-stack.ts
|
|
329
539
|
import { IntegerTable as IntegerTable2 } from "@poe-platform/safe-fs/storage";
|
|
330
|
-
import { yieldTurn as
|
|
540
|
+
import { yieldTurn as yieldTurn4 } from "../safe-bash-contracts/yield.js";
|
|
331
541
|
var magickInput = /* @__PURE__ */ Symbol("magickInput");
|
|
332
542
|
var StoredImageStack = class {
|
|
333
543
|
constructor(storage, signal, parent) {
|
|
@@ -359,7 +569,7 @@ var StoredImageStack = class {
|
|
|
359
569
|
if (source && !delays) {
|
|
360
570
|
delays = { position: this.storage.allocate(source.length * 9), length: source.length };
|
|
361
571
|
for (let start = 0; start < source.length; start += 512) {
|
|
362
|
-
await
|
|
572
|
+
await yieldTurn4(this.signal);
|
|
363
573
|
const count = Math.min(512, source.length - start), bytes = new Uint8Array(count * 9), view = new DataView(bytes.buffer);
|
|
364
574
|
for (let i = 0; i < count; i++) {
|
|
365
575
|
const value = storedDelay ? await storedDelay.at(start + i, { signal: this.signal }) : delay[start + i];
|
|
@@ -376,7 +586,7 @@ var StoredImageStack = class {
|
|
|
376
586
|
const text = JSON.stringify(record), encoder = new TextEncoder(), position = this.storage.allocate(8);
|
|
377
587
|
let size = 0;
|
|
378
588
|
for (let offset = 0; offset < text.length; ) {
|
|
379
|
-
await
|
|
589
|
+
await yieldTurn4(this.signal);
|
|
380
590
|
const bytes = new Uint8Array(4096), { read, written } = encoder.encodeInto(text.slice(offset, offset + 4097), bytes);
|
|
381
591
|
await this.storage.write(this.storage.allocate(written), bytes.subarray(0, written));
|
|
382
592
|
offset += read;
|
|
@@ -399,7 +609,7 @@ var StoredImageStack = class {
|
|
|
399
609
|
const decoder = new TextDecoder();
|
|
400
610
|
let text = "";
|
|
401
611
|
for (let offset = 0; offset < size; offset += 4096) {
|
|
402
|
-
await
|
|
612
|
+
await yieldTurn4(this.signal);
|
|
403
613
|
text += decoder.decode(await this.storage.read(position + 8 + offset, Math.min(4096, size - offset)), { stream: true });
|
|
404
614
|
}
|
|
405
615
|
const record = JSON.parse(text + decoder.decode());
|
|
@@ -448,12 +658,12 @@ var StoredImageStack = class {
|
|
|
448
658
|
const removed = new IntegerTable2(this.storage, 128);
|
|
449
659
|
let work = 0;
|
|
450
660
|
for (const index of indices) if (index >= 0 && index < this.length) {
|
|
451
|
-
if (++work % 128 === 0) await
|
|
661
|
+
if (++work % 128 === 0) await yieldTurn4(this.signal);
|
|
452
662
|
await removed.set(BigInt(index), 1n);
|
|
453
663
|
}
|
|
454
664
|
let next = 0;
|
|
455
665
|
for (let index = 0; index < this.length; index++) {
|
|
456
|
-
if (index % 128 === 0) await
|
|
666
|
+
if (index % 128 === 0) await yieldTurn4(this.signal);
|
|
457
667
|
if (await removed.get(BigInt(index))) continue;
|
|
458
668
|
if (next !== index) await this.indices.set(BigInt(next), await this.indices.get(BigInt(index)));
|
|
459
669
|
next++;
|
|
@@ -463,89 +673,11 @@ var StoredImageStack = class {
|
|
|
463
673
|
};
|
|
464
674
|
|
|
465
675
|
// packages/safe-bash-command-imagemagick/src/remap.ts
|
|
466
|
-
import { yieldTurn as
|
|
467
|
-
|
|
468
|
-
// packages/safe-bash-command-imagemagick/src/raster-backing.ts
|
|
469
|
-
import { yieldTurn as yieldTurn3 } from "../safe-bash-contracts/yield.js";
|
|
470
|
-
var RasterBackingCache = class {
|
|
471
|
-
constructor(storage, signal) {
|
|
472
|
-
this.storage = storage;
|
|
473
|
-
this.signal = signal;
|
|
474
|
-
}
|
|
475
|
-
storage;
|
|
476
|
-
signal;
|
|
477
|
-
pages = /* @__PURE__ */ new Map();
|
|
478
|
-
work = 0;
|
|
479
|
-
async allocate(length) {
|
|
480
|
-
const region = { position: this.storage.allocate(length), length }, zero = new Uint8Array(Math.min(4096, length));
|
|
481
|
-
for (let offset = 0; offset < length; offset += zero.length) {
|
|
482
|
-
if (offset % 65536 === 0) await yieldTurn3(this.signal);
|
|
483
|
-
await this.storage.write(region.position + offset, zero.subarray(0, Math.min(zero.length, length - offset)), { signal: this.signal });
|
|
484
|
-
}
|
|
485
|
-
return region;
|
|
486
|
-
}
|
|
487
|
-
async page(region, offset) {
|
|
488
|
-
this.signal.throwIfAborted();
|
|
489
|
-
if (++this.work % 16384 === 0) await yieldTurn3(this.signal);
|
|
490
|
-
const start = Math.floor(offset / 4096) * 4096, key = region.position + ":" + start;
|
|
491
|
-
let page = this.pages.get(key);
|
|
492
|
-
if (page) {
|
|
493
|
-
this.pages.delete(key);
|
|
494
|
-
this.pages.set(key, page);
|
|
495
|
-
return page;
|
|
496
|
-
}
|
|
497
|
-
if (this.pages.size === 32) {
|
|
498
|
-
const oldest = this.pages.entries().next().value;
|
|
499
|
-
if (oldest[1].dirty) await this.storage.write(oldest[1].position, oldest[1].bytes, { signal: this.signal });
|
|
500
|
-
this.pages.delete(oldest[0]);
|
|
501
|
-
}
|
|
502
|
-
const length = Math.min(4096, region.length - start), borrowed = await this.storage.read(region.position + start, length, { signal: this.signal });
|
|
503
|
-
if (borrowed.length !== length) throw new Error("Truncated raster backing");
|
|
504
|
-
const bytes = new Uint8Array(borrowed);
|
|
505
|
-
page = { position: region.position + start, bytes, view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), dirty: false };
|
|
506
|
-
this.pages.set(key, page);
|
|
507
|
-
return page;
|
|
508
|
-
}
|
|
509
|
-
async byte(region, offset) {
|
|
510
|
-
return (await this.page(region, offset)).bytes[offset % 4096];
|
|
511
|
-
}
|
|
512
|
-
async mark(region, offset) {
|
|
513
|
-
const page = await this.page(region, offset);
|
|
514
|
-
page.bytes[offset % 4096] = 1;
|
|
515
|
-
page.dirty = true;
|
|
516
|
-
}
|
|
517
|
-
async uint32(region, offset) {
|
|
518
|
-
return (await this.page(region, offset)).view.getUint32(offset % 4096, true);
|
|
519
|
-
}
|
|
520
|
-
async setUint32(region, offset, value) {
|
|
521
|
-
const page = await this.page(region, offset);
|
|
522
|
-
page.view.setUint32(offset % 4096, value, true);
|
|
523
|
-
page.dirty = true;
|
|
524
|
-
}
|
|
525
|
-
async float32(region, offset) {
|
|
526
|
-
return (await this.page(region, offset)).view.getFloat32(offset % 4096, true);
|
|
527
|
-
}
|
|
528
|
-
async setFloat32(region, offset, value) {
|
|
529
|
-
const page = await this.page(region, offset);
|
|
530
|
-
page.view.setFloat32(offset % 4096, value, true);
|
|
531
|
-
page.dirty = true;
|
|
532
|
-
}
|
|
533
|
-
async flush() {
|
|
534
|
-
for (const page of this.pages.values()) {
|
|
535
|
-
this.signal.throwIfAborted();
|
|
536
|
-
if (page.dirty) {
|
|
537
|
-
await this.storage.write(page.position, page.bytes, { signal: this.signal });
|
|
538
|
-
page.dirty = false;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
// packages/safe-bash-command-imagemagick/src/remap.ts
|
|
676
|
+
import { yieldTurn as yieldTurn5 } from "../safe-bash-contracts/yield.js";
|
|
545
677
|
async function remapStoredImage(image, paletteImage, storage, dither, signal) {
|
|
546
678
|
const palette = [], seen = /* @__PURE__ */ new Set();
|
|
547
679
|
for (let offset = 0; offset < paletteImage.width * paletteImage.height * 4 && palette.length < 256; offset += 4096) {
|
|
548
|
-
await
|
|
680
|
+
await yieldTurn5(signal);
|
|
549
681
|
const length = Math.min(4096, paletteImage.width * paletteImage.height * 4 - offset), bytes = await storage.read(paletteImage.position + offset, length, { signal });
|
|
550
682
|
if (bytes.length !== length) throw new Error("Truncated remap palette");
|
|
551
683
|
for (let i = 0; i < length && palette.length < 256; i += 4) {
|
|
@@ -560,7 +692,7 @@ async function remapStoredImage(image, paletteImage, storage, dither, signal) {
|
|
|
560
692
|
const count = image.width * image.height, cache = new RasterBackingCache(storage, signal);
|
|
561
693
|
const errors = dither ? { position: storage.allocate(count * 12), length: count * 12 } : void 0;
|
|
562
694
|
if (errors) for (let start = 0; start < count; start += 1024) {
|
|
563
|
-
await
|
|
695
|
+
await yieldTurn5(signal);
|
|
564
696
|
const length = Math.min(1024, count - start), pixels = await storage.read(image.position + start * 4, length * 4, { signal });
|
|
565
697
|
if (pixels.length !== length * 4) throw new Error("Truncated remap pixels");
|
|
566
698
|
const bytes = new Uint8Array(length * 12), view = new DataView(bytes.buffer);
|
|
@@ -569,7 +701,7 @@ async function remapStoredImage(image, paletteImage, storage, dither, signal) {
|
|
|
569
701
|
}
|
|
570
702
|
const position = storage.allocate(count * 4);
|
|
571
703
|
for (let start = 0; start < count; start += 1024) {
|
|
572
|
-
await
|
|
704
|
+
await yieldTurn5(signal);
|
|
573
705
|
const length = Math.min(1024, count - start), pixels = new Uint8Array(await storage.read(image.position + start * 4, length * 4, { signal }));
|
|
574
706
|
if (pixels.length !== length * 4) throw new Error("Truncated remap pixels");
|
|
575
707
|
for (let i = 0; i < length; i++) {
|
|
@@ -609,12 +741,15 @@ async function remapStoredImage(image, paletteImage, storage, dither, signal) {
|
|
|
609
741
|
}
|
|
610
742
|
|
|
611
743
|
// packages/safe-bash-command-imagemagick/src/floodfill.ts
|
|
612
|
-
import { yieldTurn as
|
|
613
|
-
|
|
744
|
+
import { yieldTurn as yieldTurn6 } from "../safe-bash-contracts/yield.js";
|
|
745
|
+
function matchesAlphaFloodfill(r, g, b, a, refR, refG, refB, refA, fuzz) {
|
|
746
|
+
return (a - refA) ** 2 + ((r - refR) ** 2 + (g - refG) ** 2 + (b - refB) ** 2) * (a / 255) * (refA / 255) / 3 <= 2 * fuzz ** 2;
|
|
747
|
+
}
|
|
748
|
+
async function floodfillStoredImage(image, storage, seedX, seedY, target, replacement, fuzz, signal, alphaOnly = false) {
|
|
614
749
|
const count = image.width * image.height, source = { position: image.position, length: count * 4 }, cache = new RasterBackingCache(storage, signal);
|
|
615
750
|
const start = seedY * image.width + seedX, seed = await cache.uint32(source, start * 4);
|
|
616
751
|
const r = target ? target.r : seed & 255, g = target ? target.g : seed >>> 8 & 255, b = target ? target.b : seed >>> 16 & 255;
|
|
617
|
-
const matches = (pixel) => Math.max(Math.abs((pixel & 255) - r), Math.abs((pixel >>> 8 & 255) - g), Math.abs((pixel >>> 16 & 255) - b)) <= fuzz;
|
|
752
|
+
const matches = (pixel) => alphaOnly ? matchesAlphaFloodfill(pixel & 255, pixel >>> 8 & 255, pixel >>> 16 & 255, pixel >>> 24, r, g, b, seed >>> 24, fuzz) : Math.max(Math.abs((pixel & 255) - r), Math.abs((pixel >>> 8 & 255) - g), Math.abs((pixel >>> 16 & 255) - b)) <= fuzz;
|
|
618
753
|
if (!matches(seed)) return image;
|
|
619
754
|
const visited = await cache.allocate(count), stack = await cache.allocate(count * 4);
|
|
620
755
|
let tail = 1;
|
|
@@ -631,14 +766,16 @@ async function floodfillStoredImage(image, storage, seedX, seedY, target, replac
|
|
|
631
766
|
await cache.flush();
|
|
632
767
|
const position = storage.allocate(count * 4);
|
|
633
768
|
for (let start2 = 0; start2 < count; start2 += 1024) {
|
|
634
|
-
await
|
|
769
|
+
await yieldTurn6(signal);
|
|
635
770
|
const length = Math.min(1024, count - start2), pixels = new Uint8Array(await storage.read(image.position + start2 * 4, length * 4, { signal }));
|
|
636
771
|
const flags = await storage.read(visited.position + start2, length, { signal });
|
|
637
772
|
if (pixels.length !== length * 4 || flags.length !== length) throw new Error("Truncated floodfill pixels");
|
|
638
773
|
for (let i = 0; i < length; i++) if (flags[i]) {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
774
|
+
if (!alphaOnly) {
|
|
775
|
+
pixels[i * 4] = replacement.r;
|
|
776
|
+
pixels[i * 4 + 1] = replacement.g;
|
|
777
|
+
pixels[i * 4 + 2] = replacement.b;
|
|
778
|
+
}
|
|
642
779
|
pixels[i * 4 + 3] = replacement.a;
|
|
643
780
|
}
|
|
644
781
|
await storage.write(position + start2 * 4, pixels, { signal });
|
|
@@ -816,7 +953,7 @@ function* convolvePixelSteps(image, kernel, bias) {
|
|
|
816
953
|
// packages/safe-bash-command-imagemagick/src/encoded-snapshots.ts
|
|
817
954
|
import { encodeStoredImage } from "../image-ast/portable.js";
|
|
818
955
|
import { IntegerTable as IntegerTable3 } from "@poe-platform/safe-fs/storage";
|
|
819
|
-
import { yieldTurn as
|
|
956
|
+
import { yieldTurn as yieldTurn7 } from "../safe-bash-contracts/yield.js";
|
|
820
957
|
var EncodedSnapshots = class {
|
|
821
958
|
constructor(storage, signal) {
|
|
822
959
|
this.storage = storage;
|
|
@@ -846,7 +983,7 @@ var EncodedSnapshots = class {
|
|
|
846
983
|
};
|
|
847
984
|
try {
|
|
848
985
|
while (true) {
|
|
849
|
-
await
|
|
986
|
+
await yieldTurn7(this.signal);
|
|
850
987
|
const next = await encoder.next();
|
|
851
988
|
if (next.done) {
|
|
852
989
|
if (!next.value) throw new Error("Image encoding did not finish");
|
|
@@ -858,7 +995,7 @@ var EncodedSnapshots = class {
|
|
|
858
995
|
new DataView(header.buffer).setFloat64(0, bytes.length, true);
|
|
859
996
|
await this.storage.write(position, header);
|
|
860
997
|
for (let start = 0; start < bytes.length; start += 4096) {
|
|
861
|
-
await
|
|
998
|
+
await yieldTurn7(this.signal);
|
|
862
999
|
await this.storage.write(position + 8 + start, bytes.subarray(start, start + 4096));
|
|
863
1000
|
}
|
|
864
1001
|
await this.buckets.set(hash, BigInt(position));
|
|
@@ -897,7 +1034,7 @@ var EncodedSnapshots = class {
|
|
|
897
1034
|
const decoder = new TextDecoder();
|
|
898
1035
|
let text = "";
|
|
899
1036
|
for (let start = 0; start < size; start += 4096) {
|
|
900
|
-
await
|
|
1037
|
+
await yieldTurn7(this.signal);
|
|
901
1038
|
text += decoder.decode(await this.storage.read(position + 8 + start, Math.min(4096, size - start)), { stream: true });
|
|
902
1039
|
}
|
|
903
1040
|
const record = JSON.parse(text + decoder.decode());
|
|
@@ -907,7 +1044,7 @@ var EncodedSnapshots = class {
|
|
|
907
1044
|
async find(path, hash) {
|
|
908
1045
|
let position = Number(await this.buckets.get(hash) ?? -1n);
|
|
909
1046
|
while (position >= 0) {
|
|
910
|
-
await
|
|
1047
|
+
await yieldTurn7(this.signal);
|
|
911
1048
|
const record = await this.record(position);
|
|
912
1049
|
if (record.path === path) return record;
|
|
913
1050
|
position = record.next ?? -1;
|
|
@@ -971,7 +1108,7 @@ import { FsError as FsError2 } from "@poe-platform/safe-fs/contracts";
|
|
|
971
1108
|
import { resolvePath as resolvePath2 } from "../safe-bash-contracts/path.js";
|
|
972
1109
|
import { writeBytes } from "../safe-bash-contracts/io.js";
|
|
973
1110
|
import { writeFileOutput } from "../safe-bash-contracts/filesystem-output-budget.js";
|
|
974
|
-
import { yieldTurn as
|
|
1111
|
+
import { yieldTurn as yieldTurn8 } from "../safe-bash-contracts/yield.js";
|
|
975
1112
|
var CompareInputFailure = class extends Error {
|
|
976
1113
|
constructor(reason) {
|
|
977
1114
|
super("Comparison input failed");
|
|
@@ -996,7 +1133,7 @@ async function withCompareFiles(input, stdinBytes, signal, run) {
|
|
|
996
1133
|
const { data, data16: ignored, ...metadata } = image, position = storage.allocate(data.length);
|
|
997
1134
|
for (let offset = 0; offset < data.length; offset += 16384) {
|
|
998
1135
|
if (offset % 1048576 === 0)
|
|
999
|
-
await
|
|
1136
|
+
await yieldTurn8(signal);
|
|
1000
1137
|
await storage.write(position + offset, data.subarray(offset, offset + 16384));
|
|
1001
1138
|
}
|
|
1002
1139
|
return { ...metadata, position };
|
|
@@ -1037,7 +1174,7 @@ async function withCompareFiles(input, stdinBytes, signal, run) {
|
|
|
1037
1174
|
}
|
|
1038
1175
|
const encoded = snapshot ? (async function* () {
|
|
1039
1176
|
for (let position = 0; position < snapshot.source.size; position += 16384) {
|
|
1040
|
-
await
|
|
1177
|
+
await yieldTurn8(signal);
|
|
1041
1178
|
yield new Uint8Array(await snapshot.source.read(position, Math.min(16384, snapshot.source.size - position), io));
|
|
1042
1179
|
}
|
|
1043
1180
|
})() : encodeStoredImage2(image, storage, signal, encoding), chunks = [];
|
|
@@ -1106,7 +1243,7 @@ async function withCompareFiles(input, stdinBytes, signal, run) {
|
|
|
1106
1243
|
try {
|
|
1107
1244
|
let next = iterator.next();
|
|
1108
1245
|
while (!next.done) {
|
|
1109
|
-
await
|
|
1246
|
+
await yieldTurn8(signal);
|
|
1110
1247
|
let configured = next.value, image;
|
|
1111
1248
|
try {
|
|
1112
1249
|
image = bytes ? await retain(decodeImage(bytes, configured)) : await decodeFileImage(checked, storage, fs, cwd, signal, configured);
|
|
@@ -1438,7 +1575,7 @@ async function withIdentifyFiles(input, stdinBytes, signal, run) {
|
|
|
1438
1575
|
// packages/safe-bash-command-imagemagick/src/index.ts
|
|
1439
1576
|
import { FsError as FsError4 } from "../safe-bash-contracts/errors.js";
|
|
1440
1577
|
import { resolvePath as resolvePath3 } from "../safe-bash-contracts/path.js";
|
|
1441
|
-
import { yieldTurn as
|
|
1578
|
+
import { yieldTurn as yieldTurn9, drainCooperativeSteps as drainSteps } from "../safe-bash-contracts/yield.js";
|
|
1442
1579
|
import { InputByteBudget } from "../safe-bash-contracts/io.js";
|
|
1443
1580
|
import { writeFileOutput as writeFileOutput2 } from "../safe-bash-contracts/filesystem-output-budget.js";
|
|
1444
1581
|
import {
|
|
@@ -1836,6 +1973,7 @@ function createDefaultState() {
|
|
|
1836
1973
|
quality: 92,
|
|
1837
1974
|
density: 72,
|
|
1838
1975
|
fuzz: 10,
|
|
1976
|
+
alphaFuzz: 0,
|
|
1839
1977
|
kernel: "lanczos3",
|
|
1840
1978
|
compose: "over",
|
|
1841
1979
|
composeRaw: "Over",
|
|
@@ -1955,7 +2093,7 @@ function* createRoseImageSteps() {
|
|
|
1955
2093
|
data
|
|
1956
2094
|
};
|
|
1957
2095
|
}
|
|
1958
|
-
function* applyMagickFloodfillSteps(img, geomStr, targetColor, replacement, fuzz, signal) {
|
|
2096
|
+
function* applyMagickFloodfillSteps(img, geomStr, targetColor, replacement, fuzz, signal, alphaOnly = false) {
|
|
1959
2097
|
let cooperativeWork = 0;
|
|
1960
2098
|
const g = parseMagickGeometry(geomStr);
|
|
1961
2099
|
const w = img.width;
|
|
@@ -1969,6 +2107,7 @@ function* applyMagickFloodfillSteps(img, geomStr, targetColor, replacement, fuzz
|
|
|
1969
2107
|
const refB = targetColor ? targetColor.b : out[seedOff + 2];
|
|
1970
2108
|
const matchesRef = (pIdx) => {
|
|
1971
2109
|
const off = pIdx * 4;
|
|
2110
|
+
if (alphaOnly) return matchesAlphaFloodfill(out[off], out[off + 1], out[off + 2], out[off + 3], refR, refG, refB, img.data[seedOff + 3], fuzz);
|
|
1972
2111
|
return Math.max(
|
|
1973
2112
|
Math.abs(out[off] - refR),
|
|
1974
2113
|
Math.abs(out[off + 1] - refG),
|
|
@@ -1988,9 +2127,11 @@ function* applyMagickFloodfillSteps(img, geomStr, targetColor, replacement, fuzz
|
|
|
1988
2127
|
yield;
|
|
1989
2128
|
const cur = queue[head++];
|
|
1990
2129
|
const off = cur * 4;
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2130
|
+
if (!alphaOnly) {
|
|
2131
|
+
out[off] = replacement.r;
|
|
2132
|
+
out[off + 1] = replacement.g;
|
|
2133
|
+
out[off + 2] = replacement.b;
|
|
2134
|
+
}
|
|
1994
2135
|
out[off + 3] = replacement.a;
|
|
1995
2136
|
const cx = cur % w;
|
|
1996
2137
|
const cy = Math.floor(cur / w);
|
|
@@ -4095,7 +4236,7 @@ async function decodeStoredMagickSvg(svg, density, backend, signal) {
|
|
|
4095
4236
|
const encoder = new TextEncoder(), base = backend.storage.allocate(0);
|
|
4096
4237
|
let size = 0;
|
|
4097
4238
|
for (let offset = 0; offset < svg.length; ) {
|
|
4098
|
-
await
|
|
4239
|
+
await yieldTurn9(signal);
|
|
4099
4240
|
const bytes = new Uint8Array(4096), { read, written } = encoder.encodeInto(svg.slice(offset, offset + 4097), bytes);
|
|
4100
4241
|
await backend.storage.write(backend.storage.allocate(written), bytes.subarray(0, written));
|
|
4101
4242
|
offset += read;
|
|
@@ -4207,14 +4348,14 @@ function* magickDrawSteps(img, drawCmd, state) {
|
|
|
4207
4348
|
stroke = rgbaToCss(parseColor(tokens[i++] ?? "#000000"));
|
|
4208
4349
|
} else if (cmd === "stroke-width" || cmd === "strokewidth") {
|
|
4209
4350
|
strokeWidth = Math.max(0, num());
|
|
4210
|
-
} else if (cmd === "color") {
|
|
4351
|
+
} else if (cmd === "color" || cmd === "alpha") {
|
|
4211
4352
|
const x = num(), y = num(), method = tokens[i++]?.toLowerCase();
|
|
4212
|
-
if (method !== "floodfill" || !Number.isFinite(x) || !Number.isFinite(y)) throw new Error(
|
|
4353
|
+
if (method !== "floodfill" || !Number.isFinite(x) || !Number.isFinite(y)) throw new Error(`${cmd} drawing requires finite coordinates and the floodfill method`);
|
|
4213
4354
|
if (svgElements.length > 0) {
|
|
4214
4355
|
yield { kind: "svg", svg: `<svg xmlns="http://www.w3.org/2000/svg" width="${img.width}" height="${img.height}">${svgElements.join("")}</svg>` };
|
|
4215
4356
|
svgElements.length = 0;
|
|
4216
4357
|
}
|
|
4217
|
-
yield { kind: "floodfill", x: Math.max(0, Math.min(img.width - 1, Math.round(x))), y: Math.max(0, Math.min(img.height - 1, Math.round(y))), color: parseColor(fill) };
|
|
4358
|
+
yield { kind: "floodfill", x: Math.max(0, Math.min(img.width - 1, Math.round(x))), y: Math.max(0, Math.min(img.height - 1, Math.round(y))), color: parseColor(fill), alphaOnly: cmd === "alpha" };
|
|
4218
4359
|
} else if (cmd === "rectangle") {
|
|
4219
4360
|
const x0 = num();
|
|
4220
4361
|
const y0 = num();
|
|
@@ -4764,7 +4905,7 @@ async function drainIdentifySteps(steps, signal) {
|
|
|
4764
4905
|
while (!next.done) {
|
|
4765
4906
|
try {
|
|
4766
4907
|
if (next.value) await next.value.run();
|
|
4767
|
-
else await
|
|
4908
|
+
else await yieldTurn9(signal);
|
|
4768
4909
|
next = steps.next();
|
|
4769
4910
|
} catch (error) {
|
|
4770
4911
|
next = steps.throw(error);
|
|
@@ -4961,9 +5102,15 @@ function* applyMagickLookup(image, lookup) {
|
|
|
4961
5102
|
}
|
|
4962
5103
|
return { ...image, data };
|
|
4963
5104
|
}
|
|
5105
|
+
function parseConnectedComponents(tokens, state, start) {
|
|
5106
|
+
const value = tokens[start + 1];
|
|
5107
|
+
if (tokens[start] !== "-connected-components") throw new Error(`Unsupported option: ${tokens[start]}`);
|
|
5108
|
+
if (value !== "4" && value !== "8") throw new Error("connected-components: connectivity must be 4 or 8");
|
|
5109
|
+
if (state.alphaFuzz !== 0) throw new Error("connected-components: nonzero fuzz is unsupported");
|
|
5110
|
+
return Number(value);
|
|
5111
|
+
}
|
|
4964
5112
|
function parseMagickAnalysisOperation(tokens, state, start) {
|
|
4965
5113
|
const token = tokens[start];
|
|
4966
|
-
if (token === "-connected-components") throw new Error("Unsupported option: -connected-components");
|
|
4967
5114
|
if (!["-auto-level", "-auto-gamma", "-normalize", "-contrast-stretch", "-linear-stretch", "-equalize"].includes(token ?? "")) return;
|
|
4968
5115
|
let end = start;
|
|
4969
5116
|
const argument = token === "-normalize" ? "2%x1%" : token === "-contrast-stretch" || token === "-linear-stretch" ? tokens[++end] ?? "0%x0%" : "";
|
|
@@ -5252,7 +5399,7 @@ async function transformStoredMagickPixels(image, backend, operation, signal) {
|
|
|
5252
5399
|
const size = image.width * image.height * 4, position = backend.storage.allocate(size);
|
|
5253
5400
|
let result = image;
|
|
5254
5401
|
for (let offset = 0; offset < size; offset += 16384) {
|
|
5255
|
-
if (offset % 1048576 === 0) await
|
|
5402
|
+
if (offset % 1048576 === 0) await yieldTurn9(signal);
|
|
5256
5403
|
const data = await backend.storage.read(image.position + offset, Math.min(16384, size - offset));
|
|
5257
5404
|
const transformed = await drainSteps(operation.apply({ ...image, width: data.length / 4, height: 1, data }), signal);
|
|
5258
5405
|
const { data: pixels, data16: ignored, ...metadata } = transformed;
|
|
@@ -5300,6 +5447,7 @@ function applyMagickReadSetting(tokens, state, start) {
|
|
|
5300
5447
|
state.density = Math.max(1, Math.round(g.width ?? 72));
|
|
5301
5448
|
} else if (t === "-fuzz") {
|
|
5302
5449
|
const rawFuzz = tokens[++i] ?? "10";
|
|
5450
|
+
state.alphaFuzz = rawFuzz.endsWith("%") ? parseFloat(rawFuzz) * 255 / 100 : parseFloat(rawFuzz) / 257;
|
|
5303
5451
|
state.fuzz = rawFuzz.endsWith("%") ? Math.round(parseFloat(rawFuzz) / 100 * 255) : Math.round(parseFloat(rawFuzz));
|
|
5304
5452
|
} else if (t === "-filter") {
|
|
5305
5453
|
state.kernel = parseKernel(tokens[++i] ?? "lanczos");
|
|
@@ -5309,18 +5457,24 @@ function applyMagickReadSetting(tokens, state, start) {
|
|
|
5309
5457
|
state.compose = parseCompose(cRaw);
|
|
5310
5458
|
} else if (t === "-define") {
|
|
5311
5459
|
const defStr = tokens[++i] ?? "";
|
|
5460
|
+
if (defStr.toLowerCase().startsWith("connected-components:")) {
|
|
5461
|
+
const [key, value, extra] = defStr.toLowerCase().split("=");
|
|
5462
|
+
if (extra !== void 0 || key !== "connected-components:verbose" || value !== "true" && value !== "false") throw new Error(`Unsupported connected-components define: ${defStr}`);
|
|
5463
|
+
state.connectedVerbose = value === "true";
|
|
5464
|
+
}
|
|
5312
5465
|
const m = /^compose:args=(.*)$/i.exec(defStr);
|
|
5313
5466
|
if (m)
|
|
5314
5467
|
state.composeArgs = m[1];
|
|
5315
5468
|
} else if (t === "-set") {
|
|
5316
5469
|
const k = (tokens[++i] ?? "").toLowerCase();
|
|
5317
5470
|
const v = tokens[++i] ?? "";
|
|
5471
|
+
if (k.startsWith("option:connected-components:") || k.startsWith("connected-components:")) throw new Error(`Unsupported connected-components setting: ${k}`);
|
|
5318
5472
|
if (k === "option:compose:args")
|
|
5319
5473
|
state.composeArgs = v;
|
|
5320
5474
|
} else return void 0;
|
|
5321
5475
|
return i;
|
|
5322
5476
|
}
|
|
5323
|
-
function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], stdinBytes, signal) {
|
|
5477
|
+
function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], stdinBytes, signal, analysis = { text: "" }) {
|
|
5324
5478
|
let cooperativeWork = 63;
|
|
5325
5479
|
let stack = [];
|
|
5326
5480
|
let operandsOnly = false;
|
|
@@ -5354,7 +5508,7 @@ function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], st
|
|
|
5354
5508
|
const endIdx = depth === 0 ? j - 1 : j;
|
|
5355
5509
|
const subTokens = tokens.slice(i + 1, endIdx);
|
|
5356
5510
|
const subState = { ...state };
|
|
5357
|
-
const subResult = yield* evaluatePipelineTokensSteps(subTokens, files, subState, stack, stdinBytes, signal);
|
|
5511
|
+
const subResult = yield* evaluatePipelineTokensSteps(subTokens, files, subState, stack, stdinBytes, signal, analysis);
|
|
5358
5512
|
stack.push(...subResult);
|
|
5359
5513
|
i = j;
|
|
5360
5514
|
continue;
|
|
@@ -5365,6 +5519,13 @@ function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], st
|
|
|
5365
5519
|
const analysisOperation = setting === void 0 && !pixelOperation ? parseMagickAnalysisOperation(tokens, state, i) : void 0;
|
|
5366
5520
|
if (setting !== void 0) {
|
|
5367
5521
|
i = setting;
|
|
5522
|
+
} else if (t === "-connected-components" || t === "+connected-components") {
|
|
5523
|
+
const connectivity = parseConnectedComponents(tokens, state, i++);
|
|
5524
|
+
stack = yield* mapSteps(stack, function* (image) {
|
|
5525
|
+
const result = yield* connectedComponentsSteps(image, connectivity, state.connectedVerbose ?? false);
|
|
5526
|
+
analysis.text += result.text;
|
|
5527
|
+
return result.image;
|
|
5528
|
+
});
|
|
5368
5529
|
} else if (analysisOperation) {
|
|
5369
5530
|
i = analysisOperation.end;
|
|
5370
5531
|
stack = yield* mapSteps(stack, function* (image) {
|
|
@@ -5709,7 +5870,7 @@ function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], st
|
|
|
5709
5870
|
continue;
|
|
5710
5871
|
}
|
|
5711
5872
|
if (step.kind === "shape") im = yield* applyMagickRasterSteps(im, drawShapePixelSteps(im, step), signal);
|
|
5712
|
-
else if (step.kind === "floodfill") im = yield* applyMagickFloodfillSteps(im, `+${step.x}+${step.y}`, void 0, step.color, state.fuzz, signal);
|
|
5873
|
+
else if (step.kind === "floodfill") im = yield* applyMagickFloodfillSteps(im, `+${step.x}+${step.y}`, void 0, step.color, step.alphaOnly ? state.alphaFuzz : state.fuzz, signal, step.alphaOnly);
|
|
5713
5874
|
else {
|
|
5714
5875
|
const overlay = decodeImage3(new TextEncoder().encode(step.svg), { density: state.density });
|
|
5715
5876
|
im = yield* applyMagickRasterSteps(im, drawOverlayPixelSteps(im, overlay), signal, im, [im, overlay]);
|
|
@@ -5879,6 +6040,11 @@ function* evaluatePipelineTokensSteps(tokens, files, state, parentStack = [], st
|
|
|
5879
6040
|
return stack;
|
|
5880
6041
|
}
|
|
5881
6042
|
function* runConvertCliSteps(argv, files, stdinBytes, signal) {
|
|
6043
|
+
const analysis = { text: "" };
|
|
6044
|
+
const result = yield* runConvertCliResultSteps(argv, files, stdinBytes, signal, analysis);
|
|
6045
|
+
return { ...result, stdout: analysis.text + result.stdout };
|
|
6046
|
+
}
|
|
6047
|
+
function* runConvertCliResultSteps(argv, files, stdinBytes, signal, analysis = { text: "" }) {
|
|
5882
6048
|
const listRes = tryHandleMagickListOption(argv);
|
|
5883
6049
|
if (listRes) return listRes;
|
|
5884
6050
|
let cooperativeWork = 63;
|
|
@@ -5901,7 +6067,7 @@ function* runConvertCliSteps(argv, files, stdinBytes, signal) {
|
|
|
5901
6067
|
const pipelineTokens = argv.slice(0, -1);
|
|
5902
6068
|
const state = createDefaultState();
|
|
5903
6069
|
try {
|
|
5904
|
-
const stack = yield* evaluatePipelineTokensSteps(pipelineTokens, files, state, [], stdinBytes, signal);
|
|
6070
|
+
const stack = yield* evaluatePipelineTokensSteps(pipelineTokens, files, state, [], stdinBytes, signal, analysis);
|
|
5905
6071
|
if (stack.length === 0) {
|
|
5906
6072
|
return {
|
|
5907
6073
|
exitCode: 1,
|
|
@@ -5912,6 +6078,7 @@ function* runConvertCliSteps(argv, files, stdinBytes, signal) {
|
|
|
5912
6078
|
}
|
|
5913
6079
|
const finalImg = stack[stack.length - 1];
|
|
5914
6080
|
const outLower = outSpec.toLowerCase();
|
|
6081
|
+
if (outLower === "null:") return { exitCode: 0, stdout: "", stderr: "" };
|
|
5915
6082
|
if (outLower === "info:" || outLower === "info:-") {
|
|
5916
6083
|
const formatted = [];
|
|
5917
6084
|
for (const [idx, im] of stack.entries()) {
|
|
@@ -6020,7 +6187,7 @@ async function transformStoredMagickRaster(image, backend, steps, signal, dimens
|
|
|
6020
6187
|
signal.throwIfAborted();
|
|
6021
6188
|
const request = next.value;
|
|
6022
6189
|
if (!request) {
|
|
6023
|
-
await
|
|
6190
|
+
await yieldTurn9(signal);
|
|
6024
6191
|
await checkpoint?.();
|
|
6025
6192
|
next = steps.next();
|
|
6026
6193
|
} else if (request.kind === "write") {
|
|
@@ -6051,7 +6218,7 @@ async function morphStoredMagickImage(image, backend, plan, signal) {
|
|
|
6051
6218
|
const position = backend.storage.allocate(size);
|
|
6052
6219
|
const a = images[step.a], b = images[step.b];
|
|
6053
6220
|
for (let offset = 0; offset < size; offset += 16384) {
|
|
6054
|
-
await
|
|
6221
|
+
await yieldTurn9(signal);
|
|
6055
6222
|
const length = Math.min(16384, size - offset);
|
|
6056
6223
|
const left = new Uint8Array(await backend.storage.read(a.position + offset, length));
|
|
6057
6224
|
const bytes = await drainSteps(subtractMagickPixelSteps(left, await backend.storage.read(b.position + offset, length)), signal);
|
|
@@ -6100,7 +6267,7 @@ async function transformStoredMagickCoordinates(image, backend, token, geometry,
|
|
|
6100
6267
|
let work = 0;
|
|
6101
6268
|
for (const y of ys) for (let row = 0; row < y.length; row++) for (const x of xs) {
|
|
6102
6269
|
for (let offset = 0; offset < x.length; offset += 4096) {
|
|
6103
|
-
if (work++ % 64 === 0) await
|
|
6270
|
+
if (work++ % 64 === 0) await yieldTurn9(signal);
|
|
6104
6271
|
const length = Math.min(4096, x.length - offset) * 4;
|
|
6105
6272
|
const bytes = await backend.storage.read(image.position + ((y.source + row) * w + x.source + offset) * 4, length);
|
|
6106
6273
|
await backend.storage.write(position + ((y.target + row) * width + x.target + offset) * 4, bytes);
|
|
@@ -6112,12 +6279,12 @@ async function compositeStoredMagick(base, overlay, backend, signal, left, top,
|
|
|
6112
6279
|
let hasAlpha = base.hasAlpha || !generic && !magickCompositeMode(mode).delegated;
|
|
6113
6280
|
const position = inPlace ? base.position : backend.storage.allocate(base.width * base.height * 4);
|
|
6114
6281
|
for (let start = 0; !inPlace && start < base.width * base.height * 4; start += 16384) {
|
|
6115
|
-
await
|
|
6282
|
+
await yieldTurn9(signal);
|
|
6116
6283
|
await backend.storage.write(position + start, await backend.storage.read(base.position + start, Math.min(16384, base.width * base.height * 4 - start)));
|
|
6117
6284
|
}
|
|
6118
6285
|
for (let y = Math.max(0, top); y < Math.min(base.height, top + overlay.height); y++) {
|
|
6119
6286
|
for (let x = Math.max(0, left); x < Math.min(base.width, left + overlay.width); x += 4096) {
|
|
6120
|
-
await
|
|
6287
|
+
await yieldTurn9(signal);
|
|
6121
6288
|
const count = Math.min(4096, Math.min(base.width, left + overlay.width) - x), destination = (y * base.width + x) * 4;
|
|
6122
6289
|
const dst = { ...base, width: count, height: 1, data: new Uint8Array(await backend.storage.read(position + destination, count * 4)) };
|
|
6123
6290
|
const src = { ...overlay, width: count, height: 1, data: new Uint8Array(await backend.storage.read(overlay.position + ((y - top) * overlay.width + x - left) * 4, count * 4)) };
|
|
@@ -6142,6 +6309,11 @@ async function compositeStoredMagick(base, overlay, backend, signal, left, top,
|
|
|
6142
6309
|
return { ...base, position, hasAlpha };
|
|
6143
6310
|
}
|
|
6144
6311
|
async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
6312
|
+
const analysis = { text: "" };
|
|
6313
|
+
const result = await tryConvertFilesResult(argv, input, stdinBytes, signal, analysis);
|
|
6314
|
+
return result ? { ...result, stdout: analysis.text + result.stdout } : void 0;
|
|
6315
|
+
}
|
|
6316
|
+
async function tryConvertFilesResult(argv, input, stdinBytes, signal, analysis) {
|
|
6145
6317
|
if (!input.filesystem.capabilities || !input.filesystem.open || !input.filesystem.removeFileConditional) return;
|
|
6146
6318
|
const outSpec = argv.at(-1);
|
|
6147
6319
|
const optionArgs = argv.slice(0, argv.indexOf("--") < 0 ? argv.length : argv.indexOf("--"));
|
|
@@ -6150,7 +6322,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6150
6322
|
return drainSteps(runConvertCliSteps(argv, /* @__PURE__ */ new Map(), stdinBytes, signal), signal);
|
|
6151
6323
|
}
|
|
6152
6324
|
const output = inferOutputFormat(outSpec, "png");
|
|
6153
|
-
await
|
|
6325
|
+
await yieldTurn9(signal);
|
|
6154
6326
|
let state = createDefaultState();
|
|
6155
6327
|
const tokens = argv.slice(0, -1), scopes = [];
|
|
6156
6328
|
const steps = [];
|
|
@@ -6167,7 +6339,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6167
6339
|
};
|
|
6168
6340
|
try {
|
|
6169
6341
|
for (let i = 0; i < tokens.length; i++) {
|
|
6170
|
-
if (i && i % 64 === 0) await
|
|
6342
|
+
if (i && i % 64 === 0) await yieldTurn9(signal);
|
|
6171
6343
|
const token = tokens[i];
|
|
6172
6344
|
if (token === "") continue;
|
|
6173
6345
|
if (!operandsOnly && token === "--") {
|
|
@@ -6210,19 +6382,19 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6210
6382
|
if (token.endsWith("clone") || token.endsWith("duplicate")) {
|
|
6211
6383
|
const source = stack.length ? stack : parents.at(-1) ?? stack, length = source.length;
|
|
6212
6384
|
for (let repeat = 0; repeat < count; repeat++) for (const index of parseMagickIndexSpec(spec, length)) {
|
|
6213
|
-
await
|
|
6385
|
+
await yieldTurn9(signal);
|
|
6214
6386
|
await stack.push(await source.get(index));
|
|
6215
6387
|
}
|
|
6216
6388
|
} else if (token.endsWith("delete")) await stack.remove(parseMagickIndexSpec(spec, stack.length));
|
|
6217
6389
|
else if (token === "-reverse") {
|
|
6218
6390
|
for (let n = 0; n < Math.floor(stack.length / 2); n++) {
|
|
6219
|
-
await
|
|
6391
|
+
await yieldTurn9(signal);
|
|
6220
6392
|
await stack.swap(n, stack.length - 1 - n);
|
|
6221
6393
|
}
|
|
6222
6394
|
} else if (token.endsWith("insert")) {
|
|
6223
6395
|
const raw = token === "+insert" ? 0 : Number(spec), target = raw < 0 ? Math.max(0, stack.length + raw) : Math.min(stack.length - 1, Math.max(0, raw));
|
|
6224
6396
|
for (let n = stack.length - 1; n > target; n--) {
|
|
6225
|
-
await
|
|
6397
|
+
await yieldTurn9(signal);
|
|
6226
6398
|
await stack.swap(n, n - 1);
|
|
6227
6399
|
}
|
|
6228
6400
|
} else {
|
|
@@ -6271,7 +6443,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6271
6443
|
const a = await stack.get(index), b = await stack.get(index + 1);
|
|
6272
6444
|
await result.push(a);
|
|
6273
6445
|
for (let step = 1; step <= count; step++) {
|
|
6274
|
-
await
|
|
6446
|
+
await yieldTurn9(signal);
|
|
6275
6447
|
const fraction = step / (count + 1), width = Math.max(1, Math.round(a.width * (1 - fraction) + b.width * fraction)), height = Math.max(1, Math.round(a.height * (1 - fraction) + b.height * fraction));
|
|
6276
6448
|
const first = await resize(a, width, height), last = await resize(b, width, height);
|
|
6277
6449
|
await result.push(await transformStoredMagickRaster(first, backend, interpolatePixelSteps(width * height * 4, fraction), signal, first, [first, last]));
|
|
@@ -6311,6 +6483,17 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6311
6483
|
steps.push(async (image, backend) => image ? transformStoredMagickPixels(image, backend, pixelOperation, signal) : void 0);
|
|
6312
6484
|
continue;
|
|
6313
6485
|
}
|
|
6486
|
+
if (!operandsOnly && (token === "-connected-components" || token === "+connected-components")) {
|
|
6487
|
+
const connectivity = parseConnectedComponents(tokens, state, i++), verbose = state.connectedVerbose ?? false;
|
|
6488
|
+
steps.push(async (image, backend) => {
|
|
6489
|
+
if (!image) return;
|
|
6490
|
+
const result = await connectedComponentsStored(image, backend.storage, connectivity, verbose, signal);
|
|
6491
|
+
if (input.stdout) await writeIdentifyText(input.stdout, result.text, signal);
|
|
6492
|
+
else analysis.text += result.text;
|
|
6493
|
+
return result.image;
|
|
6494
|
+
});
|
|
6495
|
+
continue;
|
|
6496
|
+
}
|
|
6314
6497
|
const analysisOperation = operandsOnly ? void 0 : parseMagickAnalysisOperation(tokens, state, i);
|
|
6315
6498
|
if (analysisOperation) {
|
|
6316
6499
|
i = analysisOperation.end;
|
|
@@ -6318,7 +6501,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6318
6501
|
if (!image) return;
|
|
6319
6502
|
const histogram = Array.from({ length: 4 }, () => new Float64Array(256)), size = image.width * image.height * 4;
|
|
6320
6503
|
for (let offset = 0; offset < size; offset += 16384) {
|
|
6321
|
-
if (offset % 1048576 === 0) await
|
|
6504
|
+
if (offset % 1048576 === 0) await yieldTurn9(signal);
|
|
6322
6505
|
await drainSteps(accumulateMagickHistogram(await backend.storage.read(image.position + offset, Math.min(16384, size - offset)), histogram), signal);
|
|
6323
6506
|
}
|
|
6324
6507
|
const lookup = analysisOperation.lookup(histogram, image);
|
|
@@ -6352,7 +6535,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6352
6535
|
if (append && stack.length === 1) return stack;
|
|
6353
6536
|
let width = 0, height = 0;
|
|
6354
6537
|
for (let n = 0; n < stack.length; n++) {
|
|
6355
|
-
await
|
|
6538
|
+
await yieldTurn9(signal);
|
|
6356
6539
|
const frame = await stack.get(n);
|
|
6357
6540
|
width = append && !vertical ? width + frame.width : Math.max(width, frame.width);
|
|
6358
6541
|
height = append && vertical ? height + frame.height : Math.max(height, frame.height);
|
|
@@ -6420,7 +6603,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6420
6603
|
const output2 = inferOutputFormat(path, image.format);
|
|
6421
6604
|
if (stack.length > 1 && (hasSceneOutputPattern(output2.path) || !adjoin)) {
|
|
6422
6605
|
for (let index = 0; index < stack.length; index++) {
|
|
6423
|
-
await
|
|
6606
|
+
await yieldTurn9(signal);
|
|
6424
6607
|
await backend.stage(await stack.get(index), formatSceneOutputPath(output2.path, index), { format: output2.format, quality });
|
|
6425
6608
|
}
|
|
6426
6609
|
} else await backend.stage(image, output2.path, { format: output2.format, quality });
|
|
@@ -6466,11 +6649,11 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6466
6649
|
if (!image) return;
|
|
6467
6650
|
for (const step of magickDrawSteps(image, drawing, settings)) {
|
|
6468
6651
|
if (!step) {
|
|
6469
|
-
await
|
|
6652
|
+
await yieldTurn9(signal);
|
|
6470
6653
|
continue;
|
|
6471
6654
|
}
|
|
6472
6655
|
if (step.kind === "shape") image = await transformStoredMagickRaster(image, backend, drawShapePixelSteps(image, step), signal);
|
|
6473
|
-
else if (step.kind === "floodfill") image = await floodfillStoredImage(image, backend.storage, step.x, step.y, void 0, step.color, settings.fuzz, signal);
|
|
6656
|
+
else if (step.kind === "floodfill") image = await floodfillStoredImage(image, backend.storage, step.x, step.y, void 0, step.color, step.alphaOnly ? settings.alphaFuzz : settings.fuzz, signal, step.alphaOnly);
|
|
6474
6657
|
else {
|
|
6475
6658
|
const overlay = await decodeStoredMagickSvg(step.svg, settings.density, backend, signal);
|
|
6476
6659
|
image = await transformStoredMagickRaster(image, backend, drawOverlayPixelSteps(image, overlay), signal, image, [image, overlay]);
|
|
@@ -6675,13 +6858,17 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6675
6858
|
return { exitCode: 1, stdout: "", stderr: `magick: no images defined '${outSpec}'
|
|
6676
6859
|
` };
|
|
6677
6860
|
}
|
|
6678
|
-
await
|
|
6861
|
+
await yieldTurn9(signal);
|
|
6862
|
+
if (outSpec.toLowerCase() === "null:") {
|
|
6863
|
+
await backend.publishPending();
|
|
6864
|
+
return { exitCode: 0, stdout: "", stderr: "" };
|
|
6865
|
+
}
|
|
6679
6866
|
const lower = outSpec.toLowerCase(), info = lower === "info:" || lower === "info:-";
|
|
6680
6867
|
if (info || lower.startsWith("txt:") || lower.startsWith("histogram:")) {
|
|
6681
6868
|
async function* information() {
|
|
6682
6869
|
let last = "";
|
|
6683
6870
|
for (let index = 0; index < stack.length; index++) {
|
|
6684
|
-
await
|
|
6871
|
+
await yieldTurn9(signal);
|
|
6685
6872
|
const frame = await stack.get(index);
|
|
6686
6873
|
if (index && !state.formatStr) yield "\n";
|
|
6687
6874
|
const text = state.formatStr ? await formatRetainedIdentify(state.formatStr, frame, { ...frame[magickInput], sceneIdx: index, sceneCount: stack.length, quality: state.quality }, async () => ({ image: frame, storage: backend.storage }), signal) : `${frame.width}x${frame.height} sRGB 8-bit`;
|
|
@@ -6707,7 +6894,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6707
6894
|
}
|
|
6708
6895
|
if (stack.length > 1 && (hasSceneOutputPattern(output.path) || !state.adjoin)) {
|
|
6709
6896
|
for (let index = 0; index < stack.length; index++) {
|
|
6710
|
-
await
|
|
6897
|
+
await yieldTurn9(signal);
|
|
6711
6898
|
await backend.stage(await stack.get(index), formatSceneOutputPath(output.path, index), { format: output.format, quality: state.quality });
|
|
6712
6899
|
}
|
|
6713
6900
|
await backend.publishPending();
|
|
@@ -6723,7 +6910,7 @@ async function tryConvertFiles(argv, input, stdinBytes, signal) {
|
|
|
6723
6910
|
frame = await transformStoredImage(frame, backend.storage, { kind: "resize", ...resize }, signal);
|
|
6724
6911
|
}
|
|
6725
6912
|
for (let offset = 0; offset < size; offset += 16384) {
|
|
6726
|
-
await
|
|
6913
|
+
await yieldTurn9(signal);
|
|
6727
6914
|
await backend.storage.write(position + index * size + offset, await backend.storage.read(frame.position + offset, Math.min(16384, size - offset)));
|
|
6728
6915
|
}
|
|
6729
6916
|
}
|
|
@@ -6971,13 +7158,13 @@ async function probeImageArguments(argv, files, stdinBytes, active) {
|
|
|
6971
7158
|
await withImageInputs(files, stdinBytes, active, async (read) => {
|
|
6972
7159
|
const inspect = async (source) => {
|
|
6973
7160
|
for (let position = 0; position < source.size; position += 16384) {
|
|
6974
|
-
await
|
|
7161
|
+
await yieldTurn9(active);
|
|
6975
7162
|
await source.read(position, Math.min(16384, source.size - position), { signal: active });
|
|
6976
7163
|
}
|
|
6977
7164
|
};
|
|
6978
7165
|
let operandsOnly = false;
|
|
6979
7166
|
for (let index = 0; index < argv.length; index++) {
|
|
6980
|
-
await
|
|
7167
|
+
await yieldTurn9(active);
|
|
6981
7168
|
const token = argv[index];
|
|
6982
7169
|
if (!operandsOnly && token === "--") {
|
|
6983
7170
|
operandsOnly = true;
|
|
@@ -7037,7 +7224,7 @@ async function parseStoredCompareInput(token, state, backend, signal, readOption
|
|
|
7037
7224
|
const [first, last] = baseToken.slice(baseToken.indexOf(":") + 1).split("-"), a = parseColor(checker ? "white" : first || "#ffffff"), b = parseColor(checker ? "black" : last || "#000000");
|
|
7038
7225
|
const cx = (width - 1) / 2, cy = (height - 1) / 2, radius = Math.max(1, Math.hypot(cx, cy));
|
|
7039
7226
|
for (let start = 0; start < width * height; start += 4096) {
|
|
7040
|
-
if (start % 262144 === 0) await
|
|
7227
|
+
if (start % 262144 === 0) await yieldTurn9(signal);
|
|
7041
7228
|
const count = Math.min(4096, width * height - start), bytes = new Uint8Array(count * 4);
|
|
7042
7229
|
for (let i = 0; i < count; i++) {
|
|
7043
7230
|
const x = (start + i) % width, y = Math.floor((start + i) / width), offset = i * 4;
|
|
@@ -7099,7 +7286,7 @@ async function parseStoredCompareInput(token, state, backend, signal, readOption
|
|
|
7099
7286
|
const width = state.sizeWidth, height = state.sizeHeight, position = backend.storage.allocate(width * height * 4);
|
|
7100
7287
|
let cachedPosition = -1, cached = new Uint8Array();
|
|
7101
7288
|
for (let start = 0; start < width * height; start += 4096) {
|
|
7102
|
-
if (start % 262144 === 0) await
|
|
7289
|
+
if (start % 262144 === 0) await yieldTurn9(signal);
|
|
7103
7290
|
const count = Math.min(4096, width * height - start), bytes = new Uint8Array(count * 4);
|
|
7104
7291
|
for (let offset = 0; offset < count; ) {
|
|
7105
7292
|
const x = (start + offset) % width, y = Math.floor((start + offset) / width), px = x % pattern.width, py = y % pattern.height, blockX = Math.floor(px / 4096) * 4096;
|
|
@@ -7660,7 +7847,7 @@ async function runMontageFiles(argv, input, stdinBytes, signal) {
|
|
|
7660
7847
|
} };
|
|
7661
7848
|
};
|
|
7662
7849
|
for (let index = 0; index < paths.length; index++) {
|
|
7663
|
-
await
|
|
7850
|
+
await yieldTurn9(signal);
|
|
7664
7851
|
const token = paths[index];
|
|
7665
7852
|
let path2 = parseInputToken(token.toLowerCase().startsWith("tile:") ? token.slice(5) : token).baseToken;
|
|
7666
7853
|
const colon = path2.indexOf(":");
|
|
@@ -7668,7 +7855,7 @@ async function runMontageFiles(argv, input, stdinBytes, signal) {
|
|
|
7668
7855
|
await backend.read(path2, async (source2) => {
|
|
7669
7856
|
const position = backend.storage.allocate(source2.size);
|
|
7670
7857
|
for (let start = 0; start < source2.size; start += 16384) {
|
|
7671
|
-
await
|
|
7858
|
+
await yieldTurn9(signal);
|
|
7672
7859
|
await backend.storage.write(position + start, await source2.read(start, Math.min(16384, source2.size - start), { signal }));
|
|
7673
7860
|
}
|
|
7674
7861
|
await sources.set(BigInt(index * 5), BigInt(position));
|
|
@@ -7698,7 +7885,7 @@ async function runMontageFiles(argv, input, stdinBytes, signal) {
|
|
|
7698
7885
|
await sources.set(BigInt(index * 5 + 3), BigInt(height));
|
|
7699
7886
|
let directPng = metadata.format === "png" && !metadata.isProgressive && prefix[24] === 8 && (prefix[25] === 2 || prefix[25] === 6), idat = false;
|
|
7700
7887
|
if (directPng) for (let offset = 8; offset + 8 <= source.size; ) {
|
|
7701
|
-
await
|
|
7888
|
+
await yieldTurn9(signal);
|
|
7702
7889
|
const header = await source.read(offset, 8), size = new DataView(header.buffer, header.byteOffset, 4).getUint32(0, false);
|
|
7703
7890
|
if (offset + 8 + size > source.size) break;
|
|
7704
7891
|
const name = String.fromCharCode(...header.subarray(4));
|
|
@@ -7752,7 +7939,7 @@ async function runMontageFiles(argv, input, stdinBytes, signal) {
|
|
|
7752
7939
|
let canvas = await createStoredCanvas(Math.max(1, cols * slotW), Math.max(1, rows * slotH), state.background, backend, signal);
|
|
7753
7940
|
let anyTransparent = state.background.a < 255 || borderW > 0 && state.borderColor.a < 255;
|
|
7754
7941
|
for (let index = 0; index < n; index++) {
|
|
7755
|
-
await
|
|
7942
|
+
await yieldTurn9(signal);
|
|
7756
7943
|
const col = index % cols, row = Math.floor(index / cols);
|
|
7757
7944
|
if (row >= rows) break;
|
|
7758
7945
|
let image, directPng = false;
|
|
@@ -7775,13 +7962,13 @@ async function runMontageFiles(argv, input, stdinBytes, signal) {
|
|
|
7775
7962
|
if (fast && borderW > 0 && state.borderColor.a > 0) {
|
|
7776
7963
|
const border = await createStoredCanvas(width, height, state.borderColor, backend, signal), empty = new Uint8Array(16384);
|
|
7777
7964
|
for (let row2 = borderW; row2 < height - borderW; row2++) for (let start = borderW; start < width - borderW; start += 4096) {
|
|
7778
|
-
await
|
|
7965
|
+
await yieldTurn9(signal);
|
|
7779
7966
|
await backend.storage.write(border.position + (row2 * width + start) * 4, empty.subarray(0, Math.min(4096, width - borderW - start) * 4));
|
|
7780
7967
|
}
|
|
7781
7968
|
canvas = await compositeStoredMagick(canvas, border, backend, signal, x, y, "over", void 0, false, true, true);
|
|
7782
7969
|
}
|
|
7783
7970
|
if (!anyTransparent) for (let start = 0; start < image.width * image.height * 4; start += 16384) {
|
|
7784
|
-
await
|
|
7971
|
+
await yieldTurn9(signal);
|
|
7785
7972
|
const bytes = await backend.storage.read(image.position + start, Math.min(16384, image.width * image.height * 4 - start));
|
|
7786
7973
|
for (let k = 3; k < bytes.length; k += 4) if (bytes[k] < 255) {
|
|
7787
7974
|
anyTransparent = true;
|
|
@@ -7867,7 +8054,7 @@ async function runBufferedImageFiles(argv, input, runner, stdinBytes, signal) {
|
|
|
7867
8054
|
const hasOutputOperand = runner !== runIdentifyCli && !(runner === runMagickCli && argv[0] === "identify");
|
|
7868
8055
|
let operandsOnly = false;
|
|
7869
8056
|
for (const [index, token] of argv.entries()) {
|
|
7870
|
-
if (++cooperativeWork % 64 === 0) await
|
|
8057
|
+
if (++cooperativeWork % 64 === 0) await yieldTurn9(context.signal);
|
|
7871
8058
|
if (!operandsOnly && token === "--") {
|
|
7872
8059
|
operandsOnly = true;
|
|
7873
8060
|
continue;
|
|
@@ -7902,7 +8089,7 @@ async function runBufferedImageFiles(argv, input, runner, stdinBytes, signal) {
|
|
|
7902
8089
|
const chunks = [];
|
|
7903
8090
|
let total = 0;
|
|
7904
8091
|
for await (const chunk of readBytes2(context.stdin, signal)) {
|
|
7905
|
-
if (++cooperativeWork % 64 === 0) await
|
|
8092
|
+
if (++cooperativeWork % 64 === 0) await yieldTurn9(context.signal);
|
|
7906
8093
|
chargeInput(chunk.byteLength);
|
|
7907
8094
|
chunks.push(chunk);
|
|
7908
8095
|
total += chunk.byteLength;
|
|
@@ -7910,7 +8097,7 @@ async function runBufferedImageFiles(argv, input, runner, stdinBytes, signal) {
|
|
|
7910
8097
|
stdinBytes = new Uint8Array(total);
|
|
7911
8098
|
let off = 0;
|
|
7912
8099
|
for (const chunk of chunks) {
|
|
7913
|
-
if (++cooperativeWork % 64 === 0) await
|
|
8100
|
+
if (++cooperativeWork % 64 === 0) await yieldTurn9(context.signal);
|
|
7914
8101
|
stdinBytes.set(chunk, off);
|
|
7915
8102
|
off += chunk.byteLength;
|
|
7916
8103
|
}
|
|
@@ -7930,7 +8117,7 @@ async function runBufferedImageFiles(argv, input, runner, stdinBytes, signal) {
|
|
|
7930
8117
|
delivered = { ...result, stdout: "" };
|
|
7931
8118
|
}
|
|
7932
8119
|
for (const [key, val] of vfsFiles.entries()) {
|
|
7933
|
-
if (++cooperativeWork % 64 === 0) await
|
|
8120
|
+
if (++cooperativeWork % 64 === 0) await yieldTurn9(context.signal);
|
|
7934
8121
|
if (existingSnap.get(key) !== val) {
|
|
7935
8122
|
const abs = resolvePath3(context.cwd, key);
|
|
7936
8123
|
await writeFileOutput2(context, val, (data) => context.fs.writeFile(abs, data, { signal }));
|