更新README文档以反映调色板数据文件的更改,移除不再使用的beadPaletteData.json文件,改为使用colorSystemMapping.json。优化page.tsx和colorSystemUtils.ts中的相关逻辑,确保色号系统选择和颜色映射功能正常工作,提升代码可读性和用户体验。

This commit is contained in:
zihanjian
2025-05-25 11:54:47 +08:00
parent 2519daf162
commit ceff488dbf
6 changed files with 81 additions and 203 deletions

View File

@@ -40,7 +40,7 @@
杂色问题的产生是因为没有进行颜色合并操作需要从未访问单元格开始使用BFS 查找欧氏距离小于阈值的邻近单元格,形成区域。将整个区域统一设置为该区域内出现次数最多的色号对应的颜色即可。
### 3⃣ 背景移除
无法进行拼豆数量统计的原因,是没有进行背景移除操作:先定义背景色号列表。从图像所有边界单元格开始执行洪水填充。将所有与边界连通且颜色属于背景色号列表的单元格标记为外部。统计和下载时将忽略这些外部单元格即可。
无法进行拼豆数量统计的原因,是没有进行背景移除操作:先定义背景色号列表。从图像所有边界单元格开始执行洪水填充。将所有与边界连通且颜色属于背景色号列表的单元格标记为"外部"。统计和下载时将忽略这些"外部"单元格即可。
### 4⃣ 颜色排除与重映射
这是杂色自动去除仍不干净的情况下的附加功能,首先确定图像处理后最初包含的所有已存在颜色。重映射时,仅在已存在颜色中排除和其他已排除颜色的子集里寻找替换色。
@@ -112,7 +112,7 @@
### 调色板数据
预设的拼豆调色板数据定义在 `src/app/beadPaletteData.json` 文件中。不同的色板组合 (如 168色、96色等) 在 `src/app/page.tsx``paletteOptions` 中定义。
预设的拼豆调色板数据定义在 `src/app/colorSystemMapping.json` 文件中该文件包含了所有颜色的hex值到各个色号系统MARD、COCO、漫漫、盼盼、咪小窝的映射关系。不同的色板组合 (如 168色、96色等) 在 `src/app/page.tsx``paletteOptions` 中定义。
## 本地开发

View File

@@ -1,51 +0,0 @@
{
"ZG1": "#DAABB3", "B16": "#C5ED9C", "D4": "#182A84", "F3": "#F74941", "H6": "#2F2B2F", "P17": "#FEA324",
"ZG2": "#D6AA87", "B17": "#9BB13A", "D5": "#B843C5", "F4": "#FC283C", "H7": "#000000", "P18": "#FEB89F",
"ZG3": "#C1BD8D", "B18": "#E6EE49", "D6": "#AC7BDE", "F5": "#E7002F", "H8": "#E7D6DB", "P19": "#FFFEEC",
"ZG4": "#96869F", "B19": "#24B88C", "D7": "#8854B3", "F6": "#943630", "H9": "#EDEDED", "P20": "#FEBECF",
"ZG5": "#8490A6", "B20": "#C2F0CC", "D8": "#E2D3FF", "F7": "#971937", "H10": "#EEE9EA", "P21": "#ECBEBF",
"ZG6": "#94BFE2", "B21": "#156A6B", "D9": "#D5B9F8", "F8": "#BC0028", "H11": "#CECDD5", "P22": "#E4A89F",
"ZG7": "#E2A9D2", "B22": "#0B3C43", "D10": "#361851", "F9": "#E2677A", "H12": "#FFF5ED", "P23": "#A56268",
"ZG8": "#AB91C0", "B23": "#303A21", "D11": "#B9BAE1", "F10": "#8A4526", "H13": "#F5ECD2", "Q1": "#F2A5E8",
"A1": "#FAF4C8", "B24": "#EEFCA5", "D12": "#DE9AD4", "F11": "#5A2121", "H14": "#CFD7D3", "Q2": "#E9EC91",
"A2": "#FFFFD5", "B25": "#4E846D", "D13": "#B90095", "F12": "#FD4E6A", "H15": "#98A6A8", "Q3": "#FFFF00",
"A3": "#FEFF8B", "B26": "#8D7A35", "D14": "#8B279B", "F13": "#F35744", "H16": "#1D1414", "Q4": "#FFEBFA",
"A4": "#FBED56", "B27": "#CCE1AF", "D15": "#2F1F90", "F14": "#FFA9AD", "H17": "#F1EDED", "Q5": "#76CEDE",
"A5": "#F4D738", "B28": "#9EE5B9", "D16": "#E3E1EE", "F15": "#D30022", "H18": "#FFFDF0", "R1": "#D50D21",
"A6": "#FEAC4C", "B29": "#C5E254", "D17": "#C4D4F6", "F16": "#FEC2A6", "H19": "#F6EFE2", "R2": "#F92F83",
"A7": "#FE8B4C", "B30": "#E2FCB1", "D18": "#A45EC7", "F17": "#E69C79", "H20": "#949FA3", "R3": "#FD8324",
"A8": "#FFDA45", "B31": "#B0E792", "D19": "#D8C3D7", "F18": "#D37C46", "H21": "#FFFBE1", "R4": "#F8EC31",
"A9": "#FF995B", "B32": "#9CAB5A", "D20": "#9C32B2", "F19": "#C1444A", "H22": "#CACAD4", "R5": "#35C75B",
"A10": "#F77C31", "C1": "#E8FFE7", "D21": "#9A009B", "F20": "#CD9391", "H23": "#9A9D94", "R6": "#238891",
"A11": "#FFDD99", "C2": "#A9F9FC", "D22": "#333A95", "F21": "#F7B4C6", "M1": "#BCC6B8", "R7": "#19779D",
"A12": "#FE9F72", "C3": "#A0E2FB", "D23": "#EBDAFC", "F22": "#FDC0D0", "M2": "#8AA386", "R8": "#1A60C3",
"A13": "#FFC365", "C4": "#41CCFF", "D24": "#7786E5", "F23": "#F67E66", "M3": "#697D80", "R9": "#9A56B4",
"A14": "#FD543D", "C5": "#01ACEB", "D25": "#494FC7", "F24": "#E698AA", "M4": "#E3D2BC", "R10": "#FFDB4C",
"A15": "#FFF365", "C6": "#50AAF0", "D26": "#DFC2F8", "F25": "#E54B4F", "M5": "#D0CCAA", "R11": "#FFEBFA",
"A16": "#FFFF9F", "C7": "#3677D2", "E1": "#FDD3CC", "G1": "#FFE2CE", "M6": "#B0A782", "R12": "#D8D5CE",
"A17": "#FFE36E", "C8": "#0F54C0", "E2": "#FEC0DF", "G2": "#FFC4AA", "M7": "#B4A497", "R13": "#55514C",
"A18": "#FEBE7D", "C9": "#324BCA", "E3": "#FFB7E7", "G3": "#F4C3A5", "M8": "#B38281", "R14": "#9FE4DF",
"A19": "#FD7C72", "C10": "#3EBCE2", "E4": "#E8649E", "G4": "#E1B383", "M9": "#A58767", "R15": "#77CEE9",
"A20": "#FFD568", "C11": "#28DDDE", "E5": "#F551A2", "G5": "#EDB045", "M10": "#C5B2BC", "R16": "#3ECFCA",
"A21": "#FFE395", "C12": "#1C334D", "E6": "#F13D74", "G6": "#E99C17", "M11": "#9F7594", "R17": "#4A867A",
"A22": "#F4F57D", "C13": "#CDE8FF", "E7": "#C63478", "G7": "#9D5B3E", "M12": "#644749", "R18": "#7FCD9D",
"A23": "#E6C9B7", "C14": "#D5FDFF", "E8": "#FFDBE9", "G8": "#753832", "M13": "#D19066", "R19": "#CDE55D",
"A24": "#F7F8A2", "C15": "#22C4C6", "E9": "#E970CC", "G9": "#E6B483", "M14": "#C77362", "R20": "#E8C7B4",
"A25": "#FFD67D", "C16": "#1557A8", "E10": "#D33793", "G10": "#D98C39", "M15": "#757D78", "R21": "#AD6F3C",
"A26": "#FFC830", "C17": "#04D1F6", "E11": "#FCDDD2", "G11": "#E0C593", "P1": "#FCF7F8", "R22": "#6C372F",
"B1": "#E6EE31", "C18": "#1D3344", "E12": "#F78FC3", "G12": "#FFC890", "P2": "#B0A9AC", "R23": "#FEB872",
"B2": "#63F347", "C19": "#1887A2", "E13": "#B5006D", "G13": "#B7714A", "P3": "#AFDCAB", "R24": "#F3C1C0",
"B3": "#9EF780", "C20": "#176DAF", "E14": "#FFD1BA", "G14": "#8D614C", "P4": "#FEA49F", "R25": "#C9675E",
"B4": "#5DE035", "C21": "#BEDDFF", "E15": "#F8C7C9", "G15": "#FCF9E0", "P5": "#EE8C3E", "R26": "#D293BE",
"B5": "#35E352", "C22": "#67B4BE", "E16": "#FFF3EB", "G16": "#F2D9BA", "P6": "#5FD0A7", "R27": "#EA8CB1",
"B6": "#65E2A6", "C23": "#C8E2FF", "E17": "#FFE2EA", "G17": "#78524B", "P7": "#EB9270", "R28": "#9C87D6",
"B7": "#3DAF80", "C24": "#7CC4FF", "E18": "#FFC7DB", "G18": "#FFE4CC", "P8": "#F0D958", "T1": "#FFFFFF",
"B8": "#1C9C4F", "C25": "#A9E5E5", "E19": "#FEBAD5", "G19": "#E07935", "P9": "#D9D9D9", "Y1": "#FD6FB4",
"B9": "#27523A", "C26": "#3CAED8", "E20": "#D8C7D1", "G20": "#A94023", "P10": "#D9C7EA", "Y2": "#FEB481",
"B10": "#95D3C2", "C27": "#D3DFFA", "E21": "#BD9DA1", "G21": "#B88558", "P11": "#F3ECC9", "Y3": "#D7FAA0",
"B11": "#5D722A", "C28": "#BBCFED", "E22": "#B785A1", "H1": "#FDFBFF", "H2": "#FEFFFF", "P12": "#E6EEF2", "Y4": "#8BDBFA",
"B12": "#166F41", "C29": "#34488E", "E23": "#937A8D", "H3": "#B6B1BA", "P13": "#AACBEF", "Y5": "#E987EA",
"B13": "#CAEB7B", "D1": "#AEB4F2", "E24": "#E1BCE8", "H4": "#89858C", "P14": "#337680",
"B14": "#ADE946", "D2": "#858EDD", "F1": "#FD957B", "H5": "#48464E", "P15": "#668575",
"B15": "#2E5132", "D3": "#2F54AF", "F2": "#FC3D46", "P16": "#FEBF45"
}

View File

@@ -20,12 +20,11 @@ import { GridDownloadOptions } from '../types/downloadTypes';
import DownloadSettingsModal, { gridLineColorOptions } from '../components/DownloadSettingsModal';
import { downloadImage } from '../utils/imageDownloader';
import beadPaletteData from './beadPaletteData.json';
import {
colorSystemOptions,
convertPaletteToColorSystem,
getDisplayColorKey,
getColorKeyByHex,
getMardToHexMapping,
ColorSystem
} from '../utils/colorSystemUtils';
@@ -63,48 +62,19 @@ function sortColorKeys(a: string, b: string): number {
}
// --- Define available palette key sets ---
const allPaletteKeys = Object.keys(beadPaletteData);
// 从colorSystemMapping.json获取所有MARD色号
const mardToHexMapping = getMardToHexMapping();
// 144 Color Palette Keys
const palette144Keys = ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1", "M1", "A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2", "M2", "A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3", "M3", "A4", "B4", "C4", "D5", "E4", "F4", "G4", "H4", "M4", "A5", "B5", "C5", "D6", "E5", "F5", "G5", "H5", "M5", "A6", "B6", "C6", "D7", "E6", "F6", "G6", "H6", "M6", "A7", "B7", "C7", "D8", "E7", "F7", "G7", "H7", "M7", "A8", "B8", "C8", "D9", "E8", "F8", "G8", "H8", "M8", "A9", "B10", "C9", "D11", "E9", "F9", "G9", "H9", "M9", "A10", "B11", "C10", "D12", "E10", "F10", "G10", "H10", "M10", "A11", "B12", "C11", "D13", "E11", "F11", "G11", "H11", "M11", "A12", "B13", "C13", "D14", "E12", "F12", "G12", "H12", "M12", "A13", "B14", "C14", "D15", "E13", "F13", "G13", "H13", "M13", "A14", "B15", "C15", "D16", "E14", "F14", "G14", "H14", "M14", "A15", "B16", "C16", "D17", "E15", "G15", "M15", "B17", "C17", "D18", "G16", "B18", "D19", "G17", "B19", "D20", "B20", "D21", "T1"]; // Ensure T1 is present
// 168 Color Palette Keys (from user table)
const palette168Keys = ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "M1", "A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2", "M2", "A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3", "M3", "A4", "B4", "C4", "D5", "E4", "F4", "G4", "H4", "M4", "A5", "B5", "C5", "D6", "E5", "F5", "G5", "H5", "M5", "A6", "B6", "C6", "D7", "E6", "F6", "G6", "H6", "M6", "A7", "B7", "C7", "D8", "E7", "F7", "G7", "H7", "M7", "A8", "B8", "C8", "D9", "E8", "F8", "G8", "H8", "M8", "A9", "B10", "C9", "D11", "E9", "F9", "G9", "H9", "M9", "A10", "B11", "C10", "D12", "E10", "F10", "G10", "H10", "M10", "A11", "B12", "C11", "D13", "E11", "F11", "G11", "H11", "M11", "A12", "B13", "C13", "D14", "E12", "F12", "G12", "H12", "M12", "A13", "B14", "C14", "D15", "E13", "F13", "G13", "H13", "M13", "A14", "B15", "C15", "D16", "E14", "F14", "G14", "H14", "M14", "A15", "B16", "C16", "D17", "E15", "G15", "M15", "B17", "C17", "D18", "G16", "B18", "D19", "G17", "B19", "D20", "B20", "D21", "T1"]; // Ensure T1 is present
// 96 Color Palette Keys (from user table)
const palette96Keys = ["A3", "A4", "A6", "A7", "A10", "A11", "A13", "A14", "B3", "B5", "B7", "B8", "B10", "B12", "B14", "B17", "B18", "B19", "B20", "C2", "C3", "C5", "C6", "C7", "C8", "C10", "C11", "C13", "C16", "D2", "D3", "D5", "D6", "D7", "D8", "D9", "D11", "D12", "D13", "D14", "D15", "D16", "D18", "D19", "D20", "D21", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E10", "E11", "E12", "E13", "E14", "E15", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "G1", "G2", "G3", "G5", "G7", "G8", "G9", "G13", "G14", "G17", "H1", "H2", "H3", "H4", "H5", "H6", "H7", "M5", "M6", "M9", "M12", "T1"]; // Added T1
// 120 Color Palette Keys (from user table)
const palette120Keys = ["A1", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B10", "B11", "B12", "B13", "B14", "B15", "B16", "B17", "B18", "B19", "B20", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C13", "C14", "C15", "C16", "C17", "D1", "D2", "D3", "D5", "D6", "D7", "D8", "D9", "D11", "D12", "D13", "D14", "D15", "D16", "D17", "D18", "D19", "D20", "D21", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E10", "E11", "E12", "E13", "E14", "E15", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "G1", "G2", "G3", "G5", "G6", "G7", "G8", "G9", "G13", "G14", "G17", "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H12", "M5", "M6", "M9", "M12", "T1"]; // Added T1
// 72 Color Palette Keys (from user table)
const palette72Keys = ["A3", "A4", "A6", "A7", "A10", "A11", "A13", "B3", "B5", "B7", "B8", "B10", "B12", "B14", "B17", "B18", "B19", "B20", "C2", "C3", "C5", "C6", "C7", "C8", "C10", "C11", "C13", "C16", "D2", "D3", "D6", "D7", "D8", "D9", "D11", "D12", "D13", "D14", "D15", "D16", "D18", "D19", "D20", "D21", "E1", "E2", "E3", "E4", "E5", "E8", "E12", "E13", "F5", "F7", "F8", "F10", "F13", "G1", "G2", "G3", "G5", "G7", "G8", "G9", "G13", "H1", "H2", "H3", "H4", "H5", "H7", "T1"]; // Added T1
// Placeholder for other palettes
// const palette48Keys = [...];
// const palette24Keys = [...];
const paletteOptions = {
'all': { name: `全色系291色`, keys: allPaletteKeys },
'168': { name: '168色', keys: palette168Keys },
'144': { name: '144色', keys: palette144Keys },
'120': { name: '120色', keys: palette120Keys },
'96': { name: '96色', keys: palette96Keys },
'72': { name: '72色', keys: palette72Keys }, // Added 72
// Add other palettes here
};
type PaletteOptionKey = keyof typeof paletteOptions;
// Pre-process the FULL palette data once
const fullBeadPalette: PaletteColor[] = Object.entries(beadPaletteData)
.map(([key, hex]) => {
// Pre-process the FULL palette data once - 使用colorSystemMapping而不是beadPaletteData
const fullBeadPalette: PaletteColor[] = Object.entries(mardToHexMapping)
.map(([mardKey, hex]) => {
const rgb = hexToRgb(hex);
if (!rgb) {
console.warn(`Invalid hex code "${hex}" for key "${key}". Skipping.`);
console.warn(`Invalid hex code "${hex}" for MARD key "${mardKey}". Skipping.`);
return null;
}
return { key, hex, rgb };
// 使用hex值作为key符合新的架构设计
return { key: hex, hex, rgb };
})
.filter((color): color is PaletteColor => color !== null);
@@ -120,7 +90,7 @@ const transparentColorData: MappedPixel = { key: TRANSPARENT_KEY, color: '#FFFFF
import PixelatedPreviewCanvas from '../components/PixelatedPreviewCanvas';
import GridTooltip from '../components/GridTooltip';
import CustomPaletteEditor from '../components/CustomPaletteEditor';
import { loadPaletteSelections, savePaletteSelections, presetToSelections, presetKeysToHexSelections, PaletteSelections } from '../utils/localStorageUtils';
import { loadPaletteSelections, savePaletteSelections, presetToSelections, PaletteSelections } from '../utils/localStorageUtils';
// 1. 导入新的 DonationModal 组件
import DonationModal from '../components/DonationModal';
@@ -133,17 +103,12 @@ export default function Home() {
const [similarityThresholdInput, setSimilarityThresholdInput] = useState<string>("30");
// 添加像素化模式状态
const [pixelationMode, setPixelationMode] = useState<PixelationMode>(PixelationMode.Dominant); // 默认为卡通模式
const [selectedPaletteKeySet, setSelectedPaletteKeySet] = useState<PaletteOptionKey>('all');
// 新增:色号系统选择状态
const [selectedColorSystem, setSelectedColorSystem] = useState<ColorSystem>('MARD');
const [activeBeadPalette, setActiveBeadPalette] = useState<PaletteColor[]>(() => {
const initialKey = 'all'; // Match the key used above
const options = paletteOptions[initialKey];
if (!options) return fullBeadPalette; // Fallback
const keySet = new Set(options.keys);
return fullBeadPalette.filter(color => keySet.has(color.key));
return fullBeadPalette; // 默认使用全部颜色
});
// 状态变量存储被排除的颜色hex值
const [excludedColorKeys, setExcludedColorKeys] = useState<Set<string>>(new Set());
@@ -194,14 +159,15 @@ export default function Home() {
// Update active palette based on selection and exclusions
useEffect(() => {
const newActiveBeadPalette = fullBeadPalette.filter(color => {
const isInSelectedPalette = paletteOptions[selectedPaletteKeySet]?.keys.includes(color.key);
const isNotExcluded = !excludedColorKeys.has(color.key);
return isInSelectedPalette && isNotExcluded;
const normalizedHex = color.hex.toUpperCase();
const isSelectedInCustomPalette = customPaletteSelections[normalizedHex];
const isNotExcluded = !excludedColorKeys.has(normalizedHex);
return isSelectedInCustomPalette && isNotExcluded;
});
// 根据选择的色号系统转换调色板
const convertedPalette = convertPaletteToColorSystem(newActiveBeadPalette, selectedColorSystem);
setActiveBeadPalette(convertedPalette);
}, [selectedPaletteKeySet, excludedColorKeys, remapTrigger, selectedColorSystem]);
}, [customPaletteSelections, excludedColorKeys, remapTrigger, selectedColorSystem]);
// ++ 添加:当状态变化时同步更新输入框的值 ++
useEffect(() => {
@@ -277,22 +243,22 @@ export default function Home() {
setIsCustomPalette(true);
} else {
console.log('所有数据都无效清除localStorage并重新初始化');
// 如果本地数据无效清除localStorage并用当前预设初始化
// 如果本地数据无效清除localStorage并默认选择所有颜色
localStorage.removeItem('customPerlerPaletteSelections');
const currentPresetKeys = paletteOptions[selectedPaletteKeySet]?.keys || [];
const initialSelections = presetKeysToHexSelections(fullBeadPalette, currentPresetKeys);
const allHexValues = fullBeadPalette.map(color => color.hex.toUpperCase());
const initialSelections = presetToSelections(allHexValues, allHexValues);
setCustomPaletteSelections(initialSelections);
setIsCustomPalette(false);
}
} else {
console.log('没有localStorage数据使用预设初始化');
// 如果没有保存的选择,用当前预设初始化
const currentPresetKeys = paletteOptions[selectedPaletteKeySet]?.keys || [];
const initialSelections = presetKeysToHexSelections(fullBeadPalette, currentPresetKeys);
console.log('没有localStorage数据默认选择所有颜色');
// 如果没有保存的选择,默认选择所有颜色
const allHexValues = fullBeadPalette.map(color => color.hex.toUpperCase());
const initialSelections = presetToSelections(allHexValues, allHexValues);
setCustomPaletteSelections(initialSelections);
setIsCustomPalette(false);
}
}, [selectedPaletteKeySet]);
}, []); // 只在组件首次加载时执行
// 更新 activeBeadPalette 基于自定义选择和排除列表
useEffect(() => {
@@ -703,7 +669,6 @@ export default function Home() {
totalBeadCount,
options: options || downloadOptions,
activeBeadPalette,
selectedPaletteKeySet,
selectedColorSystem
});
};
@@ -1097,24 +1062,6 @@ export default function Home() {
setIsCustomPalette(true);
};
// 应用预设到自定义色板
const handleApplyPreset = (presetKey: string) => {
// 检查是否为有效的预设键
if (!Object.keys(paletteOptions).includes(presetKey)) {
console.warn(`无效的预设键: ${presetKey}`);
return;
}
const typedPresetKey = presetKey as PaletteOptionKey;
const presetKeys = paletteOptions[typedPresetKey].keys || [];
const newSelections = presetKeysToHexSelections(fullBeadPalette, presetKeys);
setCustomPaletteSelections(newSelections);
setSelectedPaletteKeySet(typedPresetKey); // 同步更新预设选择状态
setIsCustomPalette(false); // 应用预设后,标记为非自定义(除非用户再次修改)
// 不要在这里关闭编辑器,让用户可以继续编辑
// setIsCustomPaletteEditorOpen(false);
};
// 保存自定义色板并应用
const handleSaveCustomPalette = () => {
savePaletteSelections(customPaletteSelections);
@@ -1517,11 +1464,8 @@ export default function Home() {
allColors={fullBeadPalette}
currentSelections={customPaletteSelections}
onSelectionChange={handleSelectionChange}
onApplyPreset={handleApplyPreset}
onSaveCustomPalette={handleSaveCustomPalette}
onClose={() => setIsCustomPaletteEditorOpen(false)}
paletteOptions={paletteOptions}
// ++ 传递新的处理函数 ++
onExportCustomPalette={handleExportCustomPalette}
onImportCustomPalette={triggerImportPalette}
selectedColorSystem={selectedColorSystem}
@@ -1550,7 +1494,7 @@ export default function Home() {
className={`w-full py-2.5 px-4 text-sm sm:text-base rounded-lg transition-all duration-200 flex items-center justify-center gap-2 bg-red-500 hover:bg-red-600 text-white shadow-sm hover:shadow-md`} // Keep red for contrast?
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" /> </svg>
</button>
{/* Color Palette (only in manual mode) */}
<div className="mt-4">
@@ -1787,7 +1731,7 @@ export default function Home() {
className={`w-full py-2.5 px-4 text-sm sm:text-base rounded-lg transition-all duration-300 flex items-center justify-center gap-2 bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white shadow-md hover:shadow-lg hover:translate-y-[-1px]`}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" /> </svg>
</button>
</div>
)} {/* ++ End of RENDER Enter Manual Mode Button ++ */}

View File

@@ -69,10 +69,8 @@ interface CustomPaletteEditorProps {
allColors: PaletteColor[];
currentSelections: PaletteSelections;
onSelectionChange: (key: string, isSelected: boolean) => void;
onApplyPreset: (presetKey: string) => void;
onSaveCustomPalette: () => void;
onClose: () => void;
paletteOptions: Record<string, { name: string; keys: string[] }>;
onExportCustomPalette: () => void;
onImportCustomPalette: () => void;
selectedColorSystem: ColorSystem;
@@ -82,10 +80,8 @@ const CustomPaletteEditor: React.FC<CustomPaletteEditorProps> = ({
allColors,
currentSelections,
onSelectionChange,
onApplyPreset,
onSaveCustomPalette,
onClose,
paletteOptions,
onExportCustomPalette,
onImportCustomPalette,
selectedColorSystem,
@@ -156,41 +152,22 @@ const CustomPaletteEditor: React.FC<CustomPaletteEditorProps> = ({
</button>
</div>
{/* 搜索和预设 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
<div>
<div className="relative">
<input
type="text"
placeholder="搜索色号..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-3 py-2 pl-9 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-200 focus:ring-blue-500 focus:border-blue-500"
/>
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-gray-500 dark:text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
{/* 搜索 */}
<div className="mb-4">
<div className="relative">
<input
type="text"
placeholder="搜索色号..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-3 py-2 pl-9 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-200 focus:ring-blue-500 focus:border-blue-500"
/>
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-gray-500 dark:text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
</div>
<div className="flex items-center gap-2">
<select
onChange={(e) => {
if (e.target.value) {
onApplyPreset(e.target.value);
}
}}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-200 focus:ring-blue-500 focus:border-blue-500"
value=""
>
<option value="" disabled>...</option>
{Object.entries(paletteOptions).map(([key, { name }]) => (
<option key={key} value={key}>{name}</option>
))}
</select>
</div>
</div>
{/* 说明文本 */}

View File

@@ -1,6 +1,5 @@
import { PaletteColor } from './pixelation';
import colorSystemMapping from '../app/colorSystemMapping.json';
import beadPaletteData from '../app/beadPaletteData.json';
// 定义色号系统类型并导出
export type ColorSystem = 'MARD' | 'COCO' | '漫漫' | '盼盼' | '咪小窝';
@@ -17,7 +16,23 @@ export const colorSystemOptions = [
// 类型定义
type ColorMapping = Record<string, Record<ColorSystem, string>>;
const typedColorSystemMapping = colorSystemMapping as ColorMapping;
const typedBeadPaletteData = beadPaletteData as Record<string, string>;
// 获取所有可用的hex值
export function getAllHexValues(): string[] {
return Object.keys(typedColorSystemMapping);
}
// 获取所有MARD色号到hex值的映射用于向后兼容
export function getMardToHexMapping(): Record<string, string> {
const mapping: Record<string, string> = {};
Object.entries(typedColorSystemMapping).forEach(([hex, colorData]) => {
const mardKey = colorData.MARD;
if (mardKey) {
mapping[mardKey] = hex;
}
});
return mapping;
}
// 从colorSystemMapping.json加载完整的颜色映射数据
export function loadFullColorMapping(): Map<string, Record<ColorSystem, string>> {
@@ -45,44 +60,39 @@ export function convertPaletteToColorSystem(
});
}
// 获取指定色号系统的显示键 - 重新设计的简化版本
export function getDisplayColorKey(originalKey: string, colorSystem: ColorSystem): string {
// 获取指定色号系统的显示键 - 基于hex值的简化版本
export function getDisplayColorKey(hexValue: string, colorSystem: ColorSystem): string {
// 对于特殊键(如透明键),直接返回原键
if (originalKey === 'ERASE' || originalKey.length === 0 || originalKey === '?') {
return originalKey;
if (hexValue === 'ERASE' || hexValue.length === 0 || hexValue === '?') {
return hexValue;
}
// 如果目标色号系统就是MARD直接返回原键
if (colorSystem === 'MARD') {
return originalKey;
}
// 标准化hex值确保大写
const normalizedHex = hexValue.toUpperCase();
// 1. 通过MARD色号从beadPaletteData获取hex
const hexValue = typedBeadPaletteData[originalKey];
if (!hexValue) {
return originalKey; // 如果找不到对应的hex值返回原键
}
// 2. 通过hex值从colorSystemMapping获取目标色号系统的值
const colorMapping = typedColorSystemMapping[hexValue];
// 通过hex值从colorSystemMapping获取目标色号系统的
const colorMapping = typedColorSystemMapping[normalizedHex];
if (colorMapping && colorMapping[colorSystem]) {
return colorMapping[colorSystem];
}
return originalKey; // 如果找不到映射,返回原键
return '?'; // 如果找不到映射,返回 '?'
}
// 将色号键转换回基础系统MARD
export function convertToBaseKey(displayKey: string, colorSystem: ColorSystem): string {
if (colorSystem === 'MARD') {
return displayKey;
// 将色号键转换到hex值支持任意色号系统
export function convertColorKeyToHex(displayKey: string, colorSystem: ColorSystem): string {
// 如果已经是hex值直接返回
if (displayKey.startsWith('#') && displayKey.length === 7) {
return displayKey.toUpperCase();
}
for (const [, mapping] of Object.entries(typedColorSystemMapping)) {
// 在colorSystemMapping中查找对应的hex值
for (const [hex, mapping] of Object.entries(typedColorSystemMapping)) {
if (mapping[colorSystem] === displayKey) {
return mapping.MARD;
return hex;
}
}
return displayKey; // 如果找不到映射,返回原键
}
@@ -103,6 +113,6 @@ export function getColorKeyByHex(hexValue: string, colorSystem: ColorSystem): st
return mapping[colorSystem];
}
// 如果找不到映射,返回 hex 值本身或者 '?'
// 如果找不到映射,返回 '?'
return '?';
}

View File

@@ -47,14 +47,13 @@ function sortColorKeys(a: string, b: string): number {
}
// 下载图片的主函数
export function downloadImage({
export async function downloadImage({
mappedPixelData,
gridDimensions,
colorCounts,
totalBeadCount,
options,
activeBeadPalette,
selectedPaletteKeySet,
selectedColorSystem
}: {
mappedPixelData: MappedPixel[][] | null;
@@ -63,9 +62,8 @@ export function downloadImage({
totalBeadCount: number;
options: GridDownloadOptions;
activeBeadPalette: PaletteColor[];
selectedPaletteKeySet: string;
selectedColorSystem: ColorSystem;
}): void {
}): Promise<void> {
if (!mappedPixelData || !gridDimensions || gridDimensions.N === 0 || gridDimensions.M === 0 || activeBeadPalette.length === 0) {
console.error("下载失败: 映射数据或尺寸无效。");
alert("无法下载图纸,数据未生成或无效。");
@@ -523,7 +521,7 @@ export function downloadImage({
try {
const dataURL = downloadCanvas.toDataURL('image/png');
const link = document.createElement('a');
link.download = `bead-grid-${N}x${M}-keys-palette_${selectedPaletteKeySet}.png`; // 文件名包含调色板
link.download = `bead-grid-${N}x${M}-keys-palette_${selectedColorSystem}.png`; // 文件名包含色彩系统
link.href = dataURL;
document.body.appendChild(link);
link.click();