From 6d8dc833543d4549b8d226ffc22309c618a42936 Mon Sep 17 00:00:00 2001 From: Zylan Date: Sat, 26 Apr 2025 11:36:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A8=AA=E8=BD=B4=E6=A0=BC?= =?UTF-8?q?=E5=AD=90=E8=BE=93=E5=85=A5=E6=A1=86=E5=8F=8A=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E6=8C=89=E9=92=AE=EF=BC=8C=E4=BC=98=E5=8C=96=E7=B2=92=E5=BA=A6?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E5=80=BC=E5=9C=A8=E6=9C=89=E6=95=88=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E5=86=85=E5=B9=B6=E5=90=8C=E6=AD=A5=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=8A=B6=E6=80=81=EF=BC=8C=E5=90=8C=E6=97=B6=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E4=BB=A5=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E5=8F=82=E6=95=B0=E4=BF=A1=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/page.tsx | 80 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index b640db1..05a054c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -57,7 +57,7 @@ const palette72Keys = ["A3", "A4", "A6", "A7", "A10", "A11", "A13", "B3", "B5", // const palette24Keys = [...]; const paletteOptions = { - 'all': { name: `221全实色`, keys: allPaletteKeys }, + 'all': { name: `全色系291色`, keys: allPaletteKeys }, '168': { name: '168色', keys: palette168Keys }, '144': { name: '144色', keys: palette144Keys }, '120': { name: '120色', keys: palette120Keys }, @@ -155,6 +155,7 @@ interface MappedPixel { export default function Home() { const [originalImageSrc, setOriginalImageSrc] = useState(null); const [granularity, setGranularity] = useState(50); // Example default + const [granularityInput, setGranularityInput] = useState("50"); // ++ 新增:输入框状态 ++ const [similarityThreshold, setSimilarityThreshold] = useState(30); // Example default for merging const [selectedPaletteKeySet, setSelectedPaletteKeySet] = useState('all'); // Use 'all' or another valid key const [activeBeadPalette, setActiveBeadPalette] = useState(() => { @@ -195,6 +196,10 @@ export default function Home() { setActiveBeadPalette(newActiveBeadPalette); }, [selectedPaletteKeySet, excludedColorKeys, remapTrigger]); // ++ 添加 remapTrigger 依赖 ++ + // ++ 添加:当granularity状态改变时同步更新输入框的值 ++ + useEffect(() => { + setGranularityInput(granularity.toString()); + }, [granularity]); // ++ Calculate unique colors currently on the grid for the palette ++ const currentGridColors = useMemo(() => { @@ -250,6 +255,10 @@ export default function Home() { setColorCounts(null); setTotalBeadCount(0); setInitialGridColorKeys(null); // ++ 重置初始键 ++ + // ++ 重置横轴格子数量为默认值 ++ + const defaultGranularity = 50; + setGranularity(defaultGranularity); + setGranularityInput(defaultGranularity.toString()); setRemapTrigger(prev => prev + 1); // Trigger full remap for new image }; reader.onerror = () => { @@ -263,13 +272,35 @@ export default function Home() { setSelectedColor(null); }; - const handleGranularityChange = (event: ChangeEvent) => { - const newGranularity = parseInt(event.target.value, 10); - setGranularity(newGranularity); - setRemapTrigger(prev => prev + 1); // Trigger full remap - // ++ Exit manual coloring mode if parameters change ++ - setIsManualColoringMode(false); - setSelectedColor(null); + // ++ 新增:处理输入框变化的函数 ++ + const handleGranularityInputChange = (event: ChangeEvent) => { + setGranularityInput(event.target.value); + }; + + // ++ 新增:处理确认按钮点击的函数 ++ + const handleConfirmGranularity = () => { + const minGranularity = 10; + const maxGranularity = 100; + let newGranularity = parseInt(granularityInput, 10); + + if (isNaN(newGranularity) || newGranularity < minGranularity) { + newGranularity = minGranularity; + } else if (newGranularity > maxGranularity) { + newGranularity = maxGranularity; + } + + // 只有在值确实改变时才触发更新 + if (newGranularity !== granularity) { + console.log(`Confirming new granularity: ${newGranularity}`); + setGranularity(newGranularity); // 更新主状态 + setRemapTrigger(prev => prev + 1); // 触发重映射 + // ++ Exit manual coloring mode if parameters change ++ + setIsManualColoringMode(false); + setSelectedColor(null); + } + + // 总是将输入框的值同步为验证后的值(避免显示非法值) + setGranularityInput(newGranularity.toString()); }; const handlePaletteChange = (event: ChangeEvent) => { @@ -297,7 +328,7 @@ export default function Home() { // Core function: Pixelate the image const pixelateImage = (imageSrc: string, detailLevel: number, threshold: number, currentPalette: PaletteColor[]) => { - console.log(`Attempting to pixelate with threshold: ${threshold}`); + console.log(`Attempting to pixelate with detail: ${detailLevel}, threshold: ${threshold}`); // ++ 修改日志,添加detail参数 ++ const originalCanvas = originalCanvasRef.current; const pixelatedCanvas = pixelatedCanvasRef.current; @@ -1202,14 +1233,31 @@ export default function Home() { {/* ++ HIDE Control Row in manual mode ++ */} {!isManualColoringMode && (
- {/* Granularity Slider */} + {/* ++ 修改:Granularity 输入框和按钮 ++ */}
- - -
-
+ +
+ e.key === 'Enter' && handleConfirmGranularity()} + className="w-full p-1.5 border border-gray-300 rounded-md text-sm focus:ring-blue-500 focus:border-blue-500 h-9" + /> + +
+
{/* Similarity Threshold Slider */}