Skip to content

Commit c87f156

Browse files
committed
fix: 素描细腻程度最小时崩溃(Maximum call stack size exceeded)
buildPencil 等处的 all.push(...P.makeRaw(...)) 用了展开语法。素描的排线是 网格播种,细腻程度拉到 0.55 时单阶段就能出 12 万条笔触,展开参数超出引擎 上限,抛 RangeError: Maximum call stack size exceeded,生成直接失败。 - 新增 appendAll() 分块追加,替换 core.js 里全部 10 处 push(...arr) - 顺带给三种大笔触风格加笔触预算(油画 13 万 / 线描 10 万 / 素描 9 万), 超出时按工序权重等比稀释,保住各阶段比例而不是砍掉某一层。 油画最细档原本 20.5 万条 / 22.7MB,现在 11 万条 / 12.5MB,画质无可见损失
1 parent 1c156d0 commit c87f156

2 files changed

Lines changed: 64 additions & 17 deletions

File tree

‎build.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
* 解决办法:所有脚本引用都带上 ?v=BUILD 查询串,每次发布改 BUILD 值即可
88
* 让浏览器当成全新 URL 去取。这里集中管理,避免各处漏改。
99
*/
10-
window.OIL_BUILD = '20261111-posterize2';
10+
window.OIL_BUILD = '20261111-spreadfix';

‎core.js‎

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@
1414
const KIND_NORMAL = 0, KIND_GLAZE = 1, KIND_SCUMBLE = 2, KIND_IMPASTO = 3, KIND_FILL = 4;
1515
const clamp = (v, a, b) => (v < a ? a : v > b ? b : v);
1616

17+
/* 安全批量追加。
18+
* 不能用 `arr.push(...big)`:笔触数量多时(素描把细腻程度拉满会到十几万条)
19+
* 会超出引擎对展开参数的限制,抛 "Maximum call stack size exceeded"。
20+
* 分块追加不受这个限制。 */
21+
function appendAll(dst, src) {
22+
const CH = 4096;
23+
for (let i = 0; i < src.length; i += CH) {
24+
const chunk = src.slice(i, i + CH);
25+
for (let j = 0; j < chunk.length; j++) dst.push(chunk[j]);
26+
}
27+
}
28+
1729
/* ---------------------------------------------------------------- 高斯 */
1830
function gaussKernel(sigma) {
1931
const r = Math.max(1, Math.ceil(sigma * 3));
@@ -754,9 +766,20 @@
754766
const stages = [];
755767
const WT = {}, LB = {};
756768
OIL_STAGE.forEach(([n, l, w]) => { WT[n] = w; LB[n] = l; });
769+
/* 笔触预算:细腻程度拉满时笔触会到 20 万条 / 22MB,手机端扛不住。
770+
* 按工序权重等比稀释,保持「大笔在前、细笔在后」的比例关系。 */
771+
const OIL_MAX = 130000;
772+
const oilW = OIL_STAGE.reduce((a, x) => a + x[2], 0);
757773
const push = (name, ss) => {
758-
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: ss });
759-
if (onStage) onStage(name, ss.length, LB[name] || name);
774+
const allow = Math.max(600, Math.round(OIL_MAX * (WT[name] || 5) / oilW));
775+
let kept = ss;
776+
if (ss.length > allow) {
777+
const stride = ss.length / allow;
778+
kept = [];
779+
for (let i = 0; i < allow; i++) kept.push(ss[Math.min(ss.length - 1, Math.floor(i * stride))]);
780+
}
781+
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: kept });
782+
if (onStage) onStage(name, kept.length, LB[name] || name);
760783
};
761784

762785
const GB = groundColor(P, W, H, { mode: 'warm', darkFrac: 0.28 });
@@ -816,7 +839,7 @@
816839
Wd.push((w0 + P.rnd() * (w1 - w0)) * s);
817840
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
818841
}
819-
all.push(...P.make(g.X, g.Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 0.8, 0.72, [70, 58, 46], 0.34, 'gris'));
842+
appendAll(all, P.make(g.X, g.Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 0.8, 0.72, [70, 58, 46], 0.34, 'gris'));
820843
}
821844
push('grisaille', all);
822845
}
@@ -833,7 +856,7 @@
833856
Wd.push((w0 + P.rnd() * (w1 - w0)) * s);
834857
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
835858
}
836-
all.push(...P.make(g.X, g.Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 1.0, 0.04, null, 0, 'block'));
859+
appendAll(all, P.make(g.X, g.Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 1.0, 0.04, null, 0, 'block'));
837860
}
838861
push('block-in', all);
839862
}
@@ -852,7 +875,7 @@
852875
Wd.push((w0 + P.rnd() * (w1 - w0)) * s);
853876
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
854877
}
855-
all.push(...P.make(X, Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 1.0, 0, null, 0, 'mass'));
878+
appendAll(all, P.make(X, Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 1.0, 0, null, 0, 'mass'));
856879
}
857880
push('massing', all);
858881
}
@@ -871,7 +894,7 @@
871894
Wd.push((w0 + P.rnd() * (w1 - w0)) * s);
872895
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
873896
}
874-
all.push(...P.make(X, Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 0.94, 0, null, 0, 'mod'));
897+
appendAll(all, P.make(X, Y, L, Wd, Lay, 5, 0, KIND_NORMAL, 0.94, 0, null, 0, 'mod'));
875898
}
876899
push('modelling', all);
877900
}
@@ -937,7 +960,7 @@
937960
Wd.push((0.85 + P.rnd() * 0.85) * s);
938961
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
939962
}
940-
det.push(...P.make(X, Y, L, Wd, Lay, 4, 1, KIND_NORMAL, 1.0, 0, null, 0, 'det'));
963+
appendAll(det, P.make(X, Y, L, Wd, Lay, 4, 1, KIND_NORMAL, 1.0, 0, null, 0, 'det'));
941964
}
942965
for (const r of rois) {
943966
const g = P.grid(5.6 * s, 0.5, [r[0] + 1.7 * s, r[1] + 1.7 * s, r[2], r[3]]);
@@ -950,7 +973,7 @@
950973
Wd.push((0.9 + P.rnd() * 0.9) * s);
951974
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
952975
}
953-
det.push(...P.make(X, Y, L, Wd, Lay, 4, 1, KIND_NORMAL, 1.0, 0, null, 0, 'det2'));
976+
appendAll(det, P.make(X, Y, L, Wd, Lay, 4, 1, KIND_NORMAL, 1.0, 0, null, 0, 'det2'));
954977
}
955978
for (const r of rois.slice(0, 5)) {
956979
const e = P.edgeSeeds(r, 0.5, 2.6 * s);
@@ -961,7 +984,7 @@
961984
Wd.push((0.8 + P.rnd() * 0.6) * s);
962985
Lay.push(P.sampleA(A.labels, e.X[i], e.Y[i]));
963986
}
964-
det.push(...P.make(e.X, e.Y, L, Wd, Lay, 3, 1, KIND_NORMAL, 1.0, 0, null, 0, 'micro'));
987+
appendAll(det, P.make(e.X, e.Y, L, Wd, Lay, 3, 1, KIND_NORMAL, 1.0, 0, null, 0, 'micro'));
965988
}
966989
push('detail', det);
967990
}
@@ -1013,9 +1036,19 @@
10131036
const stages = [];
10141037
const WT = {}, LB = {};
10151038
LINE_STAGE.forEach(([n, l, w]) => { WT[n] = w; LB[n] = l; });
1039+
/* 与油画同样的笔触预算,防止细腻程度拉满时数据量过大 */
1040+
const LINE_MAX = 100000;
1041+
const lineW = LINE_STAGE.reduce((a, x) => a + x[2], 0);
10161042
const push = (name, ss) => {
1017-
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: ss });
1018-
if (onStage) onStage(name, ss.length, LB[name] || name);
1043+
const allow = Math.max(500, Math.round(LINE_MAX * (WT[name] || 5) / lineW));
1044+
let kept = ss;
1045+
if (ss.length > allow) {
1046+
const stride = ss.length / allow;
1047+
kept = [];
1048+
for (let i = 0; i < allow; i++) kept.push(ss[Math.min(ss.length - 1, Math.floor(i * stride))]);
1049+
}
1050+
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: kept });
1051+
if (onStage) onStage(name, kept.length, LB[name] || name);
10191052
};
10201053

10211054
/* 线色:冷白。原图越暗线越亮,越亮线越柔 */
@@ -1088,7 +1121,7 @@
10881121
Wd.push(lw(0.78));
10891122
Lay.push(P.sampleA(A.labels, e.X[i], e.Y[i]));
10901123
}
1091-
all.push(...P.makeRaw(e.X, e.Y, L, Wd, Lay, 5, 1, KIND_NORMAL, 0.78,
1124+
appendAll(all, P.makeRaw(e.X, e.Y, L, Wd, Lay, 5, 1, KIND_NORMAL, 0.78,
10921125
Q => inkHex(P.lum(Q[0], Q[1])), 'line-fine',
10931126
Object.assign({}, EDGE_OPT, { edgeField: A.eFine })));
10941127
}
@@ -1408,9 +1441,23 @@
14081441
const stages = [];
14091442
const WT = {}, LB = {};
14101443
PENCIL_STAGE.forEach(([n, l, w]) => { WT[n] = w; LB[n] = l; });
1444+
1445+
/* 笔触预算:排线是网格播种,细腻程度拉满时数量会爆炸(约 20 万条 / 21MB),
1446+
* 手机端容易卡顿甚至 OOM。这里按总预算等比稀释,而不是砍掉某个阶段,
1447+
* 各阶段之间的比例关系保持不变。 */
1448+
const MAX_STROKES = 90000;
1449+
const totalWeight = PENCIL_STAGE.reduce((a, x) => a + x[2], 0);
14111450
const push = (name, ss) => {
1412-
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: ss });
1413-
if (onStage) onStage(name, ss.length, LB[name] || name);
1451+
const share = (WT[name] || 5) / totalWeight;
1452+
const allow = Math.max(300, Math.round(MAX_STROKES * share));
1453+
let kept = ss;
1454+
if (ss.length > allow) {
1455+
const stride = ss.length / allow;
1456+
kept = [];
1457+
for (let i = 0; i < allow; i++) kept.push(ss[Math.min(ss.length - 1, Math.floor(i * stride))]);
1458+
}
1459+
stages.push({ name, label: LB[name] || name, weight: WT[name] || 5, strokes: kept });
1460+
if (onStage) onStage(name, kept.length, LB[name] || name);
14141461
};
14151462

14161463
/* 石墨色:原图越暗越黑。纸张很亮,调子从 ~208 往下压 */
@@ -1450,7 +1497,7 @@
14501497
Wd.push((w0 + P.rnd() * (w1 - w0)) * s);
14511498
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
14521499
}
1453-
all.push(...P.makeRaw(X, Y, L, Wd, Lay, 6, 0, KIND_NORMAL, a,
1500+
appendAll(all, P.makeRaw(X, Y, L, Wd, Lay, 6, 0, KIND_NORMAL, a,
14541501
Q => graphite(P.lum(Q[0], Q[1]), dep), 'pc-tone', { maxTurn: 0.22 }));
14551502
}
14561503
push('tone', all);
@@ -1471,7 +1518,7 @@
14711518
Wd.push((wd + P.rnd() * 0.45) * Math.max(0.85, s));
14721519
Lay.push(P.sampleA(A.labels, g.X[i], g.Y[i]));
14731520
}
1474-
all.push(...P.makeRaw(X, Y, L, Wd, Lay, 4, 0, KIND_NORMAL, a,
1521+
appendAll(all, P.makeRaw(X, Y, L, Wd, Lay, 4, 0, KIND_NORMAL, a,
14751522
Q => graphite(P.lum(Q[0], Q[1]), 0.9), 'pc-hatch', { maxTurn: 0.16 }));
14761523
}
14771524
push('hatch', all);

0 commit comments

Comments
 (0)