Improve transition edge cleanup

This commit is contained in:
wuyanwanwu
2026-08-14 01:29:04 +08:00
parent 8c505a205c
commit daffe4daca
14 changed files with 28 additions and 22 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ input[type="range"] { accent-color: var(--green); }
.canvas-viewport { position: relative; width: 100%; aspect-ratio: 1 / 1; height: auto; min-height: 0; flex: 0 0 auto; align-self: stretch; contain: size layout; overflow: hidden; }
.canvas-stage { position: absolute; inset: 0; width: auto; height: auto; overflow: scroll; display: block; padding: 12px; cursor: grab; touch-action: none; overscroll-behavior: contain; user-select: none; scrollbar-gutter: stable; }
.canvas-stage.is-dragging { cursor: grabbing; }
.canvas-wrap { width: max-content; line-height: 0; position: relative; margin: auto; border: 1px solid var(--ink); background: white; }
.canvas-wrap { width: max-content; line-height: 0; position: relative; margin: auto; border: 1px solid var(--ink); background-color: #f7f5ef; background-image: linear-gradient(45deg, #dedbd3 25%, transparent 25%), linear-gradient(-45deg, #dedbd3 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #dedbd3 75%), linear-gradient(-45deg, transparent 75%, #dedbd3 75%); background-position: 0 0, 0 5px, 5px -5px, -5px 0; background-size: 10px 10px; }
.canvas-wrap canvas { cursor: inherit; image-rendering: pixelated; }
.pixel-tooltip { position: absolute; z-index: 5; width: max-content; max-width: 260px; padding: 9px 11px; display: grid; grid-template-columns: 14px auto; align-items: center; gap: 3px 8px; color: white; background: rgba(22, 30, 27, .94); border: 1px solid rgba(255,255,255,.2); box-shadow: 4px 4px 0 rgba(0,0,0,.2); border-radius: 3px; line-height: 1.35; pointer-events: none; }
.tooltip-swatch { width: 14px; height: 14px; grid-row: 1 / 3; border-radius: 50%; border: 1px solid rgba(255,255,255,.6); }
+11 -5
View File
@@ -360,17 +360,15 @@ function sampleDominantRegions(
function cleanThinTransitionBands(colors: Array<BeadColor | null>, width: number, height: number) {
const cleaned = [...colors];
const usage = new Map<string, number>();
colors.forEach((color) => { if (color) usage.set(color.code, (usage.get(color.code) ?? 0) + 1); });
const maximumTransitionUsage = Math.max(4, Math.ceil(width * height * 0.015));
let changed = 0;
for (let row = 0; row < height; row++) {
for (let column = 0; column < width; column++) {
const index = row * width + column;
const current = colors[index];
if (!current || (usage.get(current.code) ?? 0) > maximumTransitionUsage) continue;
if (!current) continue;
const neighbors = new Map<string, { color: BeadColor; count: number }>();
let sameColorNeighbors = 0;
for (let rowOffset = -1; rowOffset <= 1; rowOffset++) {
for (let columnOffset = -1; columnOffset <= 1; columnOffset++) {
if (rowOffset === 0 && columnOffset === 0) continue;
@@ -378,12 +376,20 @@ function cleanThinTransitionBands(colors: Array<BeadColor | null>, width: number
const neighborColumn = column + columnOffset;
if (neighborRow < 0 || neighborColumn < 0 || neighborRow >= height || neighborColumn >= width) continue;
const neighbor = colors[neighborRow * width + neighborColumn];
if (!neighbor || neighbor.code === current.code) continue;
if (!neighbor) continue;
if (neighbor.code === current.code) {
sameColorNeighbors += 1;
continue;
}
const entry = neighbors.get(neighbor.code) ?? { color: neighbor, count: 0 };
entry.count += 1;
neighbors.set(neighbor.code, entry);
}
}
// A true gradient band has broad same-color support. Anti-aliased edge
// colors form a one-cell-wide chain and have at most two same-color
// neighbors, regardless of how often that edge color occurs globally.
if (sameColorNeighbors > 2) continue;
const candidates = [...neighbors.values()].sort((a, b) => b.count - a.count).slice(0, 3);
let replacement: BeadColor | null = null;
let replacementSupport = 0;