@pixerate/editor 0.209.0 → 0.210.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-X4LUGTQX.cjs → chunk-L52VMQZS.cjs} +21 -10
- package/dist/{chunk-DWYQPL2A.js → chunk-LQ5SALHK.js} +13 -2
- package/dist/chunk-MQDIP4CF.cjs +462 -0
- package/dist/chunk-XI2NV5U7.js +462 -0
- package/dist/{chunk-3EHPLDFQ.cjs → chunk-YF3YZZ6G.cjs} +16 -453
- package/dist/{chunk-USQCKRZG.js → chunk-ZGJGSCUW.js} +8 -445
- package/dist/image-editor/content-aware-fill-session.d.cts +109 -0
- package/dist/image-editor/content-aware-fill-session.d.ts +109 -0
- package/dist/image-editor/controller.d.cts +60 -1
- package/dist/image-editor/controller.d.ts +60 -1
- package/dist/image-editor/index.cjs +620 -252
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +396 -28
- package/dist/image-editor/selection/worker.d.cts +10 -0
- package/dist/image-editor/selection/worker.d.ts +10 -0
- package/dist/image-editor/selection-worker.cjs +4 -3
- package/dist/image-editor/selection-worker.js +2 -1
- package/dist/paint/heal.d.cts +3 -1
- package/dist/paint/heal.d.ts +3 -1
- package/dist/paint/index.cjs +4 -2
- package/dist/paint/index.js +10 -8
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +20 -22
- package/skills/pixerate-image-editor/references/layer-effects.md +24 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +2 -1
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
var _chunkMQDIP4CFcjs = require('./chunk-MQDIP4CF.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
8
16
|
var _chunkPQ3H2AANcjs = require('./chunk-PQ3H2AAN.cjs');
|
|
9
17
|
|
|
10
18
|
|
|
@@ -16,444 +24,6 @@ var _chunkOLNIPTB3cjs = require('./chunk-OLNIPTB3.cjs');
|
|
|
16
24
|
|
|
17
25
|
var _chunk474IQG74cjs = require('./chunk-474IQG74.cjs');
|
|
18
26
|
|
|
19
|
-
// src/paint/heal.ts
|
|
20
|
-
var TOL = 2e-3;
|
|
21
|
-
var FINE_ITERS = 30;
|
|
22
|
-
var FINE_OMEGA = 1.7;
|
|
23
|
-
function solveMembrane(w, h, unknown, v) {
|
|
24
|
-
if (unknown.length !== w * h || v.length !== w * h) throw new RangeError(`solveMembrane: expected ${w * h} cells, got ${unknown.length} and ${v.length}.`);
|
|
25
|
-
const u = new Uint8Array(w * h);
|
|
26
|
-
for (let i = 0; i < u.length; i++) u[i] = unknown[i] ? 1 : 0;
|
|
27
|
-
solveLevel(w, h, u, v, 0);
|
|
28
|
-
}
|
|
29
|
-
function solveLevel(w, h, unknown, v, depth) {
|
|
30
|
-
let nUnknown = 0;
|
|
31
|
-
let knownSum = 0;
|
|
32
|
-
let nKnown = 0;
|
|
33
|
-
for (let i = 0; i < unknown.length; i++) {
|
|
34
|
-
if (unknown[i]) nUnknown++;
|
|
35
|
-
else {
|
|
36
|
-
knownSum += v[i];
|
|
37
|
-
nKnown++;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (nUnknown === 0 || nKnown === 0) return;
|
|
41
|
-
if (w >= 8 && h >= 8 && nUnknown > 64 && depth < 16) {
|
|
42
|
-
const cw = Math.ceil(w / 2);
|
|
43
|
-
const chh = Math.ceil(h / 2);
|
|
44
|
-
const cu = new Uint8Array(cw * chh).fill(1);
|
|
45
|
-
const cv = new Float32Array(cw * chh);
|
|
46
|
-
for (let cy = 0; cy < chh; cy++) {
|
|
47
|
-
for (let cx = 0; cx < cw; cx++) {
|
|
48
|
-
let s = 0;
|
|
49
|
-
let n = 0;
|
|
50
|
-
for (let k = 0; k < 4; k++) {
|
|
51
|
-
const x = cx * 2 + (k & 1);
|
|
52
|
-
const y = cy * 2 + (k >> 1);
|
|
53
|
-
if (x < w && y < h && !unknown[y * w + x]) {
|
|
54
|
-
s += v[y * w + x];
|
|
55
|
-
n++;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (n > 0) {
|
|
59
|
-
cu[cy * cw + cx] = 0;
|
|
60
|
-
cv[cy * cw + cx] = s / n;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
solveLevel(cw, chh, cu, cv, depth + 1);
|
|
65
|
-
for (let y = 0; y < h; y++) {
|
|
66
|
-
const fy = Math.min(chh - 1, Math.max(0, (y + 0.5) / 2 - 0.5));
|
|
67
|
-
const y0 = Math.floor(fy);
|
|
68
|
-
const y1 = Math.min(chh - 1, y0 + 1);
|
|
69
|
-
const ty = fy - y0;
|
|
70
|
-
for (let x = 0; x < w; x++) {
|
|
71
|
-
if (!unknown[y * w + x]) continue;
|
|
72
|
-
const fx = Math.min(cw - 1, Math.max(0, (x + 0.5) / 2 - 0.5));
|
|
73
|
-
const x0 = Math.floor(fx);
|
|
74
|
-
const x1 = Math.min(cw - 1, x0 + 1);
|
|
75
|
-
const tx = fx - x0;
|
|
76
|
-
const a = cv[y0 * cw + x0] + (cv[y0 * cw + x1] - cv[y0 * cw + x0]) * tx;
|
|
77
|
-
const b = cv[y1 * cw + x0] + (cv[y1 * cw + x1] - cv[y1 * cw + x0]) * tx;
|
|
78
|
-
v[y * w + x] = a + (b - a) * ty;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
sor(w, h, unknown, v, FINE_ITERS, FINE_OMEGA);
|
|
82
|
-
} else {
|
|
83
|
-
const mean = knownSum / nKnown;
|
|
84
|
-
for (let i = 0; i < v.length; i++) if (unknown[i]) v[i] = mean;
|
|
85
|
-
sor(w, h, unknown, v, 2e3, 1.85);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function sor(w, h, unknown, v, maxIter, omega) {
|
|
89
|
-
let n = 0;
|
|
90
|
-
for (let i = 0; i < unknown.length; i++) if (unknown[i]) n++;
|
|
91
|
-
const cells = new Uint32Array(n);
|
|
92
|
-
const masks = new Uint8Array(n);
|
|
93
|
-
for (let i = 0, k = 0; i < unknown.length; i++) {
|
|
94
|
-
if (!unknown[i]) continue;
|
|
95
|
-
const x = i % w;
|
|
96
|
-
const y = (i - x) / w;
|
|
97
|
-
cells[k] = i;
|
|
98
|
-
masks[k++] = (x > 0 ? 1 : 0) | (x + 1 < w ? 2 : 0) | (y > 0 ? 4 : 0) | (y + 1 < h ? 8 : 0);
|
|
99
|
-
}
|
|
100
|
-
for (let it = 0; it < maxIter; it++) {
|
|
101
|
-
let maxD = 0;
|
|
102
|
-
for (let k = 0; k < n; k++) {
|
|
103
|
-
const i = cells[k];
|
|
104
|
-
const m = masks[k];
|
|
105
|
-
let s;
|
|
106
|
-
let c;
|
|
107
|
-
if (m === 15) {
|
|
108
|
-
s = v[i - 1] + v[i + 1] + v[i - w] + v[i + w];
|
|
109
|
-
c = 4;
|
|
110
|
-
} else {
|
|
111
|
-
s = 0;
|
|
112
|
-
c = 0;
|
|
113
|
-
if (m & 1) s += v[i - 1], c++;
|
|
114
|
-
if (m & 2) s += v[i + 1], c++;
|
|
115
|
-
if (m & 4) s += v[i - w], c++;
|
|
116
|
-
if (m & 8) s += v[i + w], c++;
|
|
117
|
-
if (c === 0) continue;
|
|
118
|
-
}
|
|
119
|
-
const d = omega * (s / c - v[i]);
|
|
120
|
-
v[i] += d;
|
|
121
|
-
const ad = d < 0 ? -d : d;
|
|
122
|
-
if (ad > maxD) maxD = ad;
|
|
123
|
-
}
|
|
124
|
-
if (maxD < TOL) break;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function seamlessClone(w, h, ch, src, dst, mask) {
|
|
128
|
-
const n = w * h;
|
|
129
|
-
if (src.length !== n * ch || dst.length !== n * ch || mask.length !== n) throw new RangeError("seamlessClone: src, dst and mask must cover w \xD7 h pixels.");
|
|
130
|
-
const out = new Float32Array(n * ch);
|
|
131
|
-
const hv = new Float32Array(n);
|
|
132
|
-
for (let c = 0; c < ch; c++) {
|
|
133
|
-
for (let i = 0; i < n; i++) hv[i] = mask[i] ? 0 : dst[i * ch + c] - src[i * ch + c];
|
|
134
|
-
solveMembrane(w, h, mask, hv);
|
|
135
|
-
for (let i = 0; i < n; i++) out[i * ch + c] = mask[i] ? src[i * ch + c] + hv[i] : dst[i * ch + c];
|
|
136
|
-
}
|
|
137
|
-
return out;
|
|
138
|
-
}
|
|
139
|
-
function membraneFill(w, h, ch, img, hole) {
|
|
140
|
-
const n = w * h;
|
|
141
|
-
const out = new Float32Array(n * ch);
|
|
142
|
-
const v = new Float32Array(n);
|
|
143
|
-
for (let c = 0; c < ch; c++) {
|
|
144
|
-
for (let i = 0; i < n; i++) v[i] = hole[i] ? 0 : img[i * ch + c];
|
|
145
|
-
solveMembrane(w, h, hole, v);
|
|
146
|
-
for (let i = 0; i < n; i++) out[i * ch + c] = v[i];
|
|
147
|
-
}
|
|
148
|
-
return out;
|
|
149
|
-
}
|
|
150
|
-
function dilateMask(w, h, mask, r) {
|
|
151
|
-
const tmp = new Uint8Array(w * h);
|
|
152
|
-
for (let y = 0; y < h; y++) {
|
|
153
|
-
for (let x = 0; x < w; x++) {
|
|
154
|
-
if (!mask[y * w + x]) continue;
|
|
155
|
-
for (let xx = Math.max(0, x - r); xx <= Math.min(w - 1, x + r); xx++) tmp[y * w + xx] = 1;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const out = new Uint8Array(w * h);
|
|
159
|
-
for (let y = 0; y < h; y++) {
|
|
160
|
-
for (let x = 0; x < w; x++) {
|
|
161
|
-
if (!tmp[y * w + x]) continue;
|
|
162
|
-
for (let yy = Math.max(0, y - r); yy <= Math.min(h - 1, y + r); yy++) out[yy * w + x] = 1;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return out;
|
|
166
|
-
}
|
|
167
|
-
var MaskIntegral = class {
|
|
168
|
-
constructor(w, h, mask) {
|
|
169
|
-
this.w = w;
|
|
170
|
-
this.h = h;
|
|
171
|
-
const W = w + 1;
|
|
172
|
-
this.s = new Uint32Array(W * (h + 1));
|
|
173
|
-
for (let y = 0; y < h; y++) {
|
|
174
|
-
let row = 0;
|
|
175
|
-
for (let x = 0; x < w; x++) {
|
|
176
|
-
row += mask[y * w + x] ? 1 : 0;
|
|
177
|
-
this.s[(y + 1) * W + x + 1] = this.s[y * W + x + 1] + row;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
/** Masked cells in [x0, x1) × [y0, y1) (clipped to the grid). */
|
|
185
|
-
count(x0, y0, x1, y1) {
|
|
186
|
-
const W = this.w + 1;
|
|
187
|
-
const a = Math.max(0, Math.min(this.w, x0));
|
|
188
|
-
const b = Math.max(0, Math.min(this.h, y0));
|
|
189
|
-
const c = Math.max(0, Math.min(this.w, x1));
|
|
190
|
-
const d = Math.max(0, Math.min(this.h, y1));
|
|
191
|
-
if (c <= a || d <= b) return 0;
|
|
192
|
-
return this.s[d * W + c] - this.s[b * W + c] - this.s[d * W + a] + this.s[b * W + a];
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
function maskBounds(w, h, mask) {
|
|
196
|
-
let x0 = w;
|
|
197
|
-
let y0 = h;
|
|
198
|
-
let x1 = -1;
|
|
199
|
-
let y1 = -1;
|
|
200
|
-
for (let y = 0; y < h; y++) {
|
|
201
|
-
for (let x = 0; x < w; x++) {
|
|
202
|
-
if (!mask[y * w + x]) continue;
|
|
203
|
-
if (x < x0) x0 = x;
|
|
204
|
-
if (x > x1) x1 = x;
|
|
205
|
-
if (y < y0) y0 = y;
|
|
206
|
-
if (y > y1) y1 = y;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return x1 < 0 ? null : [x0, y0, x1 + 1, y1 + 1];
|
|
210
|
-
}
|
|
211
|
-
function bestOffset(w, h, ch, img, hole, ring, maxRadius) {
|
|
212
|
-
const bb = maskBounds(w, h, hole);
|
|
213
|
-
if (!bb) return null;
|
|
214
|
-
const extent = Math.max(w, h);
|
|
215
|
-
const R = Math.max(0, Math.min(extent, Math.floor(maxRadius)));
|
|
216
|
-
if (R === 0) return null;
|
|
217
|
-
const rg = Math.max(1, Math.min(extent, Math.floor(ring)));
|
|
218
|
-
const hs = new MaskIntegral(w, h, hole);
|
|
219
|
-
const x0 = bb[0] - rg;
|
|
220
|
-
const y0 = bb[1] - rg;
|
|
221
|
-
const x1 = bb[2] + rg;
|
|
222
|
-
const y1 = bb[3] + rg;
|
|
223
|
-
const pts = [];
|
|
224
|
-
for (let y = Math.max(0, y0); y < Math.min(h, y1); y++) {
|
|
225
|
-
for (let x = Math.max(0, x0); x < Math.min(w, x1); x++) {
|
|
226
|
-
if (hole[y * w + x]) continue;
|
|
227
|
-
if (hs.count(x - rg, y - rg, x + rg + 1, y + rg + 1) > 0) pts.push(x, y);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
const stride = Math.max(1, Math.floor(pts.length / 2 / 2e3));
|
|
231
|
-
const sx = [];
|
|
232
|
-
const sy = [];
|
|
233
|
-
for (let i = 0; i < pts.length; i += 2 * stride) {
|
|
234
|
-
sx.push(pts[i]);
|
|
235
|
-
sy.push(pts[i + 1]);
|
|
236
|
-
}
|
|
237
|
-
const n = Math.max(1, sx.length);
|
|
238
|
-
const evalAt = (dx, dy, cutoff) => {
|
|
239
|
-
if (dx === 0 && dy === 0) return null;
|
|
240
|
-
const hx0 = x0 + dx;
|
|
241
|
-
const hy0 = y0 + dy;
|
|
242
|
-
const hx1 = x1 + dx;
|
|
243
|
-
const hy1 = y1 + dy;
|
|
244
|
-
if (hx0 < 0 || hy0 < 0 || hx1 > w || hy1 > h) return null;
|
|
245
|
-
if (hs.count(hx0, hy0, hx1, hy1) !== 0) return null;
|
|
246
|
-
const penalty = 1 + 1e-3 * (Math.hypot(dx, dy) / R);
|
|
247
|
-
let e = 0;
|
|
248
|
-
for (let i = 0; i < sx.length; i++) {
|
|
249
|
-
const a = (sy[i] * w + sx[i]) * ch;
|
|
250
|
-
const b = ((sy[i] + dy) * w + sx[i] + dx) * ch;
|
|
251
|
-
for (let c = 0; c < ch; c++) {
|
|
252
|
-
const d = img[a + c] - img[b + c];
|
|
253
|
-
e += d * d;
|
|
254
|
-
}
|
|
255
|
-
if ((i & 31) === 31 && e / n * penalty >= cutoff) return null;
|
|
256
|
-
}
|
|
257
|
-
return e / n * penalty;
|
|
258
|
-
};
|
|
259
|
-
const found = { best: null, e: Infinity };
|
|
260
|
-
const consider = (dx, dy) => {
|
|
261
|
-
const e = evalAt(dx, dy, found.e);
|
|
262
|
-
if (e !== null && e < found.e) {
|
|
263
|
-
found.e = e;
|
|
264
|
-
found.best = [dx, dy];
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
const step = Math.max(1, Math.floor(R / 24));
|
|
268
|
-
for (let dy = -R; dy <= R; dy += step) for (let dx = -R; dx <= R; dx += step) consider(dx, dy);
|
|
269
|
-
if (step > 1 && found.best) {
|
|
270
|
-
const [bx, by] = found.best;
|
|
271
|
-
for (let dy = by - step; dy <= by + step; dy++) for (let dx = bx - step; dx <= bx + step; dx++) consider(dx, dy);
|
|
272
|
-
}
|
|
273
|
-
return found.best;
|
|
274
|
-
}
|
|
275
|
-
var PATCH_R = 3;
|
|
276
|
-
function rng(seed) {
|
|
277
|
-
let a = seed >>> 0;
|
|
278
|
-
return () => {
|
|
279
|
-
a = a + 1831565813 >>> 0;
|
|
280
|
-
let t = a;
|
|
281
|
-
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
282
|
-
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
283
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
function downsample(l, ch) {
|
|
287
|
-
const w = Math.max(1, l.w >> 1);
|
|
288
|
-
const h = Math.max(1, l.h >> 1);
|
|
289
|
-
const img = new Float32Array(w * h * ch);
|
|
290
|
-
const hole = new Uint8Array(w * h);
|
|
291
|
-
for (let y = 0; y < h; y++) {
|
|
292
|
-
for (let x = 0; x < w; x++) {
|
|
293
|
-
let n = 0;
|
|
294
|
-
const o = (y * w + x) * ch;
|
|
295
|
-
for (let dy = 0; dy < 2; dy++) {
|
|
296
|
-
for (let dx = 0; dx < 2; dx++) {
|
|
297
|
-
const sx = Math.min(l.w - 1, 2 * x + dx);
|
|
298
|
-
const sy = Math.min(l.h - 1, 2 * y + dy);
|
|
299
|
-
const i = sy * l.w + sx;
|
|
300
|
-
if (l.hole[i]) {
|
|
301
|
-
hole[y * w + x] = 1;
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
for (let c = 0; c < ch; c++) img[o + c] += l.img[i * ch + c];
|
|
305
|
-
n++;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
if (n) for (let c = 0; c < ch; c++) img[o + c] /= n;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return { w, h, img, hole };
|
|
312
|
-
}
|
|
313
|
-
function contentAwareFill(w, h, ch, img, hole, options = {}) {
|
|
314
|
-
const iters = _nullishCoalesce(options.iterations, () => ( 4));
|
|
315
|
-
const base = { w, h, img: Float32Array.from(img), hole: Uint8Array.from(hole, (v) => v ? 1 : 0) };
|
|
316
|
-
const levels = [base];
|
|
317
|
-
while (levels.length < 4) {
|
|
318
|
-
const top = levels[levels.length - 1];
|
|
319
|
-
const b = maskBounds(top.w, top.h, top.hole);
|
|
320
|
-
if (!b || Math.max(b[2] - b[0], b[3] - b[1]) < 4 * PATCH_R || top.w < 8 * PATCH_R || top.h < 8 * PATCH_R) break;
|
|
321
|
-
levels.push(downsample(top, ch));
|
|
322
|
-
}
|
|
323
|
-
const random = rng(_nullishCoalesce(options.seed, () => ( w * 73856093 + h * 19349663)));
|
|
324
|
-
let prevFill = null;
|
|
325
|
-
let prevNnf = null;
|
|
326
|
-
let prevW = 0;
|
|
327
|
-
for (let li = levels.length - 1; li >= 0; li--) {
|
|
328
|
-
const { w: W, h: H, hole: holeL } = levels[li];
|
|
329
|
-
const cur = new Float32Array(levels[li].img);
|
|
330
|
-
if (prevFill) {
|
|
331
|
-
for (let i = 0; i < W * H; i++) {
|
|
332
|
-
if (!holeL[i]) continue;
|
|
333
|
-
const x = Math.min(prevW - 1, i % W >> 1);
|
|
334
|
-
const y = Math.min(Math.floor(prevFill.length / ch / prevW) - 1, Math.floor(i / W) >> 1);
|
|
335
|
-
for (let c = 0; c < ch; c++) cur[i * ch + c] = prevFill[(y * prevW + x) * ch + c];
|
|
336
|
-
}
|
|
337
|
-
} else cur.set(membraneFill(W, H, ch, cur, holeL));
|
|
338
|
-
const blocked = dilateMask(W, H, holeL, PATCH_R);
|
|
339
|
-
const valid = [];
|
|
340
|
-
for (let y = PATCH_R; y < H - PATCH_R; y++) for (let x = PATCH_R; x < W - PATCH_R; x++) if (!blocked[y * W + x]) valid.push(y * W + x);
|
|
341
|
-
if (!valid.length) {
|
|
342
|
-
prevFill = cur;
|
|
343
|
-
prevNnf = null;
|
|
344
|
-
prevW = W;
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
const targets = [];
|
|
348
|
-
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) if (blocked[y * W + x]) targets.push(y * W + x);
|
|
349
|
-
const nnf = new Int32Array(W * H).fill(-1);
|
|
350
|
-
const cost = new Float64Array(W * H);
|
|
351
|
-
const clampC = (v, n) => Math.min(n - 1 - PATCH_R, Math.max(PATCH_R, v));
|
|
352
|
-
const dist = (t, s, limit) => {
|
|
353
|
-
const tx = clampC(t % W, W);
|
|
354
|
-
const ty = clampC(Math.floor(t / W), H);
|
|
355
|
-
const sx = s % W;
|
|
356
|
-
const sy = Math.floor(s / W);
|
|
357
|
-
let d = 0;
|
|
358
|
-
for (let dy = -PATCH_R; dy <= PATCH_R; dy++) {
|
|
359
|
-
const tr = (ty + dy) * W;
|
|
360
|
-
const sr = (sy + dy) * W;
|
|
361
|
-
for (let dx = -PATCH_R; dx <= PATCH_R; dx++) {
|
|
362
|
-
const a = (tr + tx + dx) * ch;
|
|
363
|
-
const b = (sr + sx + dx) * ch;
|
|
364
|
-
for (let c = 0; c < ch; c++) {
|
|
365
|
-
const e = cur[a + c] - cur[b + c];
|
|
366
|
-
d += e * e;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
if (d >= limit) return d;
|
|
370
|
-
}
|
|
371
|
-
return d;
|
|
372
|
-
};
|
|
373
|
-
const isValid = (s) => {
|
|
374
|
-
const x = s % W;
|
|
375
|
-
const y = Math.floor(s / W);
|
|
376
|
-
return s >= 0 && x >= PATCH_R && y >= PATCH_R && x < W - PATCH_R && y < H - PATCH_R && !blocked[s];
|
|
377
|
-
};
|
|
378
|
-
for (const t of targets) {
|
|
379
|
-
let s = -1;
|
|
380
|
-
if (prevNnf) {
|
|
381
|
-
const px = Math.min(prevW - 1, t % W >> 1);
|
|
382
|
-
const py = Math.floor(t / W) >> 1;
|
|
383
|
-
const ps = prevNnf[py * prevW + px];
|
|
384
|
-
if (ps >= 0) {
|
|
385
|
-
const cand = (Math.floor(ps / prevW) * 2 + (Math.floor(t / W) & 1)) * W + ps % prevW * 2 + (t % W & 1);
|
|
386
|
-
if (isValid(cand)) s = cand;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (s < 0) s = valid[Math.floor(random() * valid.length)];
|
|
390
|
-
nnf[t] = s;
|
|
391
|
-
}
|
|
392
|
-
for (let em = 0; em < iters; em++) {
|
|
393
|
-
for (const t of targets) cost[t] = dist(t, nnf[t], Infinity);
|
|
394
|
-
for (let pass = 0; pass < 4; pass++) {
|
|
395
|
-
const fwd = pass % 2 === 0;
|
|
396
|
-
const step = fwd ? 1 : -1;
|
|
397
|
-
for (let k = 0; k < targets.length; k++) {
|
|
398
|
-
const t = targets[fwd ? k : targets.length - 1 - k];
|
|
399
|
-
const tx = t % W;
|
|
400
|
-
const ty = Math.floor(t / W);
|
|
401
|
-
for (const [nx, ny] of [[tx - step, ty], [tx, ty - step]]) {
|
|
402
|
-
if (nx < 0 || ny < 0 || nx >= W || ny >= H) continue;
|
|
403
|
-
const ns = nnf[ny * W + nx];
|
|
404
|
-
if (ns < 0) continue;
|
|
405
|
-
const cand = ns + step * (nx === tx ? W : 1);
|
|
406
|
-
if (!isValid(cand) || cand === nnf[t]) continue;
|
|
407
|
-
const d = dist(t, cand, cost[t]);
|
|
408
|
-
if (d < cost[t]) {
|
|
409
|
-
cost[t] = d;
|
|
410
|
-
nnf[t] = cand;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
const bx = nnf[t] % W;
|
|
414
|
-
const by = Math.floor(nnf[t] / W);
|
|
415
|
-
for (let r = Math.max(W, H); r >= 1; r >>= 1) {
|
|
416
|
-
const cx = Math.round(bx + (random() * 2 - 1) * r);
|
|
417
|
-
const cy = Math.round(by + (random() * 2 - 1) * r);
|
|
418
|
-
const cand = cy * W + cx;
|
|
419
|
-
if (cx < 0 || cy < 0 || cx >= W || cy >= H || !isValid(cand)) continue;
|
|
420
|
-
const d = dist(t, cand, cost[t]);
|
|
421
|
-
if (d < cost[t]) {
|
|
422
|
-
cost[t] = d;
|
|
423
|
-
nnf[t] = cand;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
const acc = new Float64Array(W * H * ch);
|
|
429
|
-
const wsum = new Float64Array(W * H);
|
|
430
|
-
for (const t of targets) {
|
|
431
|
-
const tx = clampC(t % W, W);
|
|
432
|
-
const ty = clampC(Math.floor(t / W), H);
|
|
433
|
-
const s = nnf[t];
|
|
434
|
-
const sx = s % W;
|
|
435
|
-
const sy = Math.floor(s / W);
|
|
436
|
-
for (let dy = -PATCH_R; dy <= PATCH_R; dy++) {
|
|
437
|
-
for (let dx = -PATCH_R; dx <= PATCH_R; dx++) {
|
|
438
|
-
const q = (ty + dy) * W + tx + dx;
|
|
439
|
-
if (!holeL[q]) continue;
|
|
440
|
-
const src = ((sy + dy) * W + sx + dx) * ch;
|
|
441
|
-
for (let c = 0; c < ch; c++) acc[q * ch + c] += cur[src + c];
|
|
442
|
-
wsum[q] += 1;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
for (let q = 0; q < W * H; q++) if (holeL[q] && wsum[q] > 0) for (let c = 0; c < ch; c++) cur[q * ch + c] = acc[q * ch + c] / wsum[q];
|
|
447
|
-
}
|
|
448
|
-
prevFill = cur;
|
|
449
|
-
prevNnf = nnf;
|
|
450
|
-
prevW = W;
|
|
451
|
-
}
|
|
452
|
-
const out = Float32Array.from(img);
|
|
453
|
-
for (let i = 0; i < w * h; i++) if (base.hole[i]) for (let c = 0; c < ch; c++) out[i * ch + c] = prevFill[i * ch + c];
|
|
454
|
-
return out;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
27
|
// src/paint/retouch.ts
|
|
458
28
|
var TONE_RANGES = ["shadows", "midtones", "highlights"];
|
|
459
29
|
function luma(r, g, b) {
|
|
@@ -895,7 +465,7 @@ function toneOf(tool, settings) {
|
|
|
895
465
|
}
|
|
896
466
|
function healPixels(w, h, src, dst, mask) {
|
|
897
467
|
const out = new Float32Array(dst);
|
|
898
|
-
const bb = maskBounds(w, h, mask);
|
|
468
|
+
const bb = _chunkMQDIP4CFcjs.maskBounds.call(void 0, w, h, mask);
|
|
899
469
|
if (!bb) return out;
|
|
900
470
|
const x0 = Math.max(0, bb[0] - 1);
|
|
901
471
|
const y0 = Math.max(0, bb[1] - 1);
|
|
@@ -917,7 +487,7 @@ function healPixels(w, h, src, dst, mask) {
|
|
|
917
487
|
}
|
|
918
488
|
}
|
|
919
489
|
}
|
|
920
|
-
const healed = seamlessClone(rw, rh, 4, s, d, m);
|
|
490
|
+
const healed = _chunkMQDIP4CFcjs.seamlessClone.call(void 0, rw, rh, 4, s, d, m);
|
|
921
491
|
for (let y = 0; y < rh; y++) {
|
|
922
492
|
for (let x = 0; x < rw; x++) {
|
|
923
493
|
const gi = ((y + y0) * w + x + x0) * 4;
|
|
@@ -928,13 +498,13 @@ function healPixels(w, h, src, dst, mask) {
|
|
|
928
498
|
return out;
|
|
929
499
|
}
|
|
930
500
|
function spotHealPixels(w, h, img, hole, size, type, onOffset) {
|
|
931
|
-
const domain = dilateMask(w, h, hole, 2);
|
|
932
|
-
const healMask = dilateMask(w, h, hole, 1);
|
|
501
|
+
const domain = _chunkMQDIP4CFcjs.dilateMask.call(void 0, w, h, hole, 2);
|
|
502
|
+
const healMask = _chunkMQDIP4CFcjs.dilateMask.call(void 0, w, h, hole, 1);
|
|
933
503
|
let filled = null;
|
|
934
504
|
let bestFound = null;
|
|
935
505
|
if (type === "proximity-match") {
|
|
936
506
|
const ring = Math.min(16, Math.max(3, Math.floor(size / 8)));
|
|
937
|
-
const off = bestOffset(w, h, 4, img, domain, ring, Math.floor(Math.max(w, h) / 2));
|
|
507
|
+
const off = _chunkMQDIP4CFcjs.bestOffset.call(void 0, w, h, 4, img, domain, ring, Math.floor(Math.max(w, h) / 2));
|
|
938
508
|
if (off) {
|
|
939
509
|
bestFound = off;
|
|
940
510
|
filled = new Float32Array(img);
|
|
@@ -949,8 +519,8 @@ function spotHealPixels(w, h, img, hole, size, type, onOffset) {
|
|
|
949
519
|
}
|
|
950
520
|
}
|
|
951
521
|
_optionalChain([onOffset, 'optionalCall', _ => _(filled ? bestFound : null)]);
|
|
952
|
-
if (!filled && type === "content-aware") filled = contentAwareFill(w, h, 4, img, domain);
|
|
953
|
-
if (!filled) filled = membraneFill(w, h, 4, img, domain);
|
|
522
|
+
if (!filled && type === "content-aware") filled = _chunkMQDIP4CFcjs.contentAwareFill.call(void 0, w, h, 4, img, domain);
|
|
523
|
+
if (!filled) filled = _chunkMQDIP4CFcjs.membraneFill.call(void 0, w, h, 4, img, domain);
|
|
954
524
|
return healPixels(w, h, filled, img, healMask);
|
|
955
525
|
}
|
|
956
526
|
function spotHealWindow(bounds, canvas) {
|
|
@@ -1127,11 +697,4 @@ function unionRect(a, b) {
|
|
|
1127
697
|
|
|
1128
698
|
|
|
1129
699
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
exports.solveMembrane = solveMembrane; exports.seamlessClone = seamlessClone; exports.membraneFill = membraneFill; exports.dilateMask = dilateMask; exports.maskBounds = maskBounds; exports.bestOffset = bestOffset; exports.contentAwareFill = contentAwareFill; exports.TONE_RANGES = TONE_RANGES; exports.luma = luma; exports.dodgeBurnCurve = dodgeBurnCurve; exports.dodgeBurn = dodgeBurn; exports.saturationOf = saturationOf; exports.sponge = sponge; exports.perDabStrength = perDabStrength; exports.RETOUCH_SAMPLES = RETOUCH_SAMPLES; exports.SPOT_HEAL_TYPES = SPOT_HEAL_TYPES; exports.DEFAULT_RETOUCH = DEFAULT_RETOUCH; exports.normalizeRetouch = normalizeRetouch; exports.boxBlurPixels = boxBlurPixels; exports.retouchFilter = retouchFilter; exports.IDENTITY_CLONE_TRANSFORM = IDENTITY_CLONE_TRANSFORM; exports.isIdentityCloneTransform = isIdentityCloneTransform; exports.cloneSamplePoint = cloneSamplePoint; exports.TransformedPixelSource = TransformedPixelSource; exports.TilePixelSource = TilePixelSource; exports.RegionPixelSource = RegionPixelSource; exports.readSourceRegion = readSourceRegion; exports.applyRetouchToTile = applyRetouchToTile; exports.applyToneToDeepTile = applyToneToDeepTile; exports.toneOf = toneOf; exports.healPixels = healPixels; exports.spotHealPixels = spotHealPixels; exports.spotHealWindow = spotHealWindow; exports.RetouchDabStroke = RetouchDabStroke; exports.smudgeEffect = smudgeEffect; exports.spongeEffect = spongeEffect; exports.rgbaViewOfGrey = rgbaViewOfGrey;
|
|
700
|
+
exports.TONE_RANGES = TONE_RANGES; exports.luma = luma; exports.dodgeBurnCurve = dodgeBurnCurve; exports.dodgeBurn = dodgeBurn; exports.saturationOf = saturationOf; exports.sponge = sponge; exports.perDabStrength = perDabStrength; exports.RETOUCH_SAMPLES = RETOUCH_SAMPLES; exports.SPOT_HEAL_TYPES = SPOT_HEAL_TYPES; exports.DEFAULT_RETOUCH = DEFAULT_RETOUCH; exports.normalizeRetouch = normalizeRetouch; exports.boxBlurPixels = boxBlurPixels; exports.retouchFilter = retouchFilter; exports.IDENTITY_CLONE_TRANSFORM = IDENTITY_CLONE_TRANSFORM; exports.isIdentityCloneTransform = isIdentityCloneTransform; exports.cloneSamplePoint = cloneSamplePoint; exports.TransformedPixelSource = TransformedPixelSource; exports.TilePixelSource = TilePixelSource; exports.RegionPixelSource = RegionPixelSource; exports.readSourceRegion = readSourceRegion; exports.applyRetouchToTile = applyRetouchToTile; exports.applyToneToDeepTile = applyToneToDeepTile; exports.toneOf = toneOf; exports.healPixels = healPixels; exports.spotHealPixels = spotHealPixels; exports.spotHealWindow = spotHealWindow; exports.RetouchDabStroke = RetouchDabStroke; exports.smudgeEffect = smudgeEffect; exports.spongeEffect = spongeEffect; exports.rgbaViewOfGrey = rgbaViewOfGrey;
|