From af3c4d0c3d0ec173fcdb8a98efebe1577d38ff3f Mon Sep 17 00:00:00 2001 From: zihanjian Date: Fri, 26 Dec 2025 16:48:23 +0800 Subject: [PATCH] feat: add auto background removal functionality --- src/app/page.tsx | 113 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/app/page.tsx b/src/app/page.tsx index 94611c5..4df9732 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1199,6 +1199,105 @@ export default function Home() { setSelectedColor(null); }; + // 一键去背景:识别边缘主色并洪水填充去除 + const handleAutoRemoveBackground = () => { + if (!mappedPixelData || !gridDimensions) { + alert('请先生成图纸后再使用一键去背景。'); + return; + } + + const { N, M } = gridDimensions; + const borderCounts = new Map(); + + const countBorderCell = (row: number, col: number) => { + const cell = mappedPixelData[row]?.[col]; + if (!cell || cell.isExternal || cell.key === TRANSPARENT_KEY) return; + borderCounts.set(cell.key, (borderCounts.get(cell.key) || 0) + 1); + }; + + for (let col = 0; col < N; col++) { + countBorderCell(0, col); + if (M > 1) countBorderCell(M - 1, col); + } + for (let row = 1; row < M - 1; row++) { + countBorderCell(row, 0); + if (N > 1) countBorderCell(row, N - 1); + } + + if (borderCounts.size === 0) { + alert('边缘没有可识别的背景颜色。'); + return; + } + + let targetKey = ''; + let maxCount = -1; + borderCounts.forEach((count, key) => { + if (count > maxCount) { + maxCount = count; + targetKey = key; + } + }); + + const newPixelData = mappedPixelData.map(row => row.map(cell => ({ ...cell }))); + const visited = Array(M).fill(null).map(() => Array(N).fill(false)); + const stack: { row: number; col: number }[] = []; + + const pushIfTarget = (row: number, col: number) => { + if (row < 0 || row >= M || col < 0 || col >= N || visited[row][col]) { + return; + } + const cell = newPixelData[row][col]; + if (!cell || cell.isExternal || cell.key !== targetKey) return; + visited[row][col] = true; + stack.push({ row, col }); + }; + + for (let col = 0; col < N; col++) { + pushIfTarget(0, col); + if (M > 1) pushIfTarget(M - 1, col); + } + for (let row = 1; row < M - 1; row++) { + pushIfTarget(row, 0); + if (N > 1) pushIfTarget(row, N - 1); + } + + if (stack.length === 0) { + alert('未找到可去除的背景区域。'); + return; + } + + while (stack.length > 0) { + const { row, col } = stack.pop()!; + newPixelData[row][col] = { ...transparentColorData }; + pushIfTarget(row - 1, col); + pushIfTarget(row + 1, col); + pushIfTarget(row, col - 1); + pushIfTarget(row, col + 1); + } + + setMappedPixelData(newPixelData); + + const newColorCounts: { [hexKey: string]: { count: number; color: string } } = {}; + let newTotalCount = 0; + newPixelData.flat().forEach(cell => { + if (cell && !cell.isExternal && cell.key !== TRANSPARENT_KEY) { + const cellHex = cell.color.toUpperCase(); + if (!newColorCounts[cellHex]) { + newColorCounts[cellHex] = { + count: 0, + color: cellHex + }; + } + newColorCounts[cellHex].count++; + newTotalCount++; + } + }); + + setColorCounts(newColorCounts); + setTotalBeadCount(newTotalCount); + setInitialGridColorKeys(new Set(Object.keys(newColorCounts))); + }; + // --- Tooltip Logic --- // --- Canvas Interaction --- @@ -2097,6 +2196,20 @@ export default function Home() { + {/* 一键去背景 */} +
+ +
+ {/* 色号系统选择器 */}