更新 README.md,优化功能描述,增加智能像素化、颜色合并、背景处理等新特性,提升用户体验和工具的可用性。

This commit is contained in:
Zylan
2025-04-25 13:21:57 +08:00
parent 3b368dd819
commit 43a2b37262

127
README.md
View File

@@ -1,88 +1,82 @@
# 拼豆底稿生成器
> Perler Beads Generator (Palette Mapping Edition)
# 拼豆底稿生成器 (Perler Beads Generator)
一个基于 Web 的工具,可以将普通图片转换为适配Mard特定调色板拼豆颜色的像素画图纸。用户可以上传图片,调整像素化粒度,预览效果,并下载带有颜色编码的网格图纸和对应的 JSON 数据
一个基于 Web 的工具,可以将普通图片转换为适配特定拼豆调色板的像素画图纸。用户可以上传图片,调整像素化粒度、颜色合并阈值,选择预设色板,排除特定颜色,预览效果,并下载带有颜色编码的图纸和用量统计图
## 功能特点
* **图片上传**: 支持拖放或点击选择 JPG/PNG 图片。
* **可调粒度**: 通过滑块控制像素化的精细程度(网格宽度)。
* **颜色映射**: 将图像颜色自动映射到预定义的拼豆调色板
* **实时预览**: 在网页上即时显示映射后的像素画预览(带网格线,无颜色编码)
* **带 Key 图纸下载**: 下载带有颜色编码Key和网格线的清晰 PNG 图纸。
* **JSON 数据下载**: 下载包含每个格子对应颜色编码的二维数组 JSON 文件
* **智能像素化**:
* **可调粒度**: 通过滑块控制像素画的横向格子数量
* **颜色合并**: 通过滑块调整相似颜色的合并阈值,平滑色块区域
* **多色板支持**:
* 提供多种预设拼豆色板 (如 168色, 144色, 96色等) 可供选择
* 根据所选色板进行颜色映射。
* **颜色排除与管理**:
* 在颜色统计列表中点击可**排除/恢复**特定颜色。
* 排除颜色后,原使用该颜色的区域将智能重映射到邻近的可用颜色。
* 提供一键恢复所有排除颜色的功能。
* **实时预览**:
* 即时显示处理后的像素画预览。
* **悬停/长按交互**: 在预览图上悬停(桌面)或长按(移动)可查看对应单元格的颜色编码 (Key) 和颜色。
* 自动识别并标记外部背景区域(预览时显示为浅灰色)。
* **下载成品**:
* **带 Key 图纸**: 下载带有清晰颜色编码 (Key) 和网格线的 PNG 图纸,忽略外部背景。
* **颜色统计图**: 下载包含各颜色 Key、色块、所需数量的 PNG 统计图。
## 技术实现
* **框架**: [Next.js](https://nextjs.org/) (React) 与 TypeScript
* **样式**: [Tailwind CSS](https://tailwindcss.com/) 用于响应式布局和样式。
* **核心逻辑**: 浏览器端 [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) 用于图像处理和绘制。
* **核心逻辑**: 浏览器端 [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) 用于图像处理、颜色分析和绘制。
* **状态管理**: React Hooks (`useState`, `useRef`, `useEffect`, `useMemo`)。
### 核心算法:像素化颜色映射
### 核心算法:像素化颜色映射与优化
应用程序的核心在于将任意图像颜色精确映射到有限的拼豆调色板上。主要步骤如下:
应用程序的核心是将图像转换为像素网格,并将颜色精确映射到有限的拼豆调色板,同时进行平滑和背景处理。
1. **图像加载与预处理**:
* 用户上传图片后,使用 `FileReader` 将其读取为 Data URL
* 创建一个 `Image` 对象加载该 URL
1. **图像加载与网格划分**:
* 加载用户上传图片。
* 根据用户选择的"粒度"(`granularity`, N) 和原图宽高比确定 `N x M` 的网格尺寸
2. **网格划分**:
* 根据用户选择的"精细度"(`granularity`) 确定像素画在宽度方向上的格子数量 `N`
* 根据原图的宽高比计算高度方向的格子数量 `M = round(N * height / width)`,确保 `M` 至少为 1
2. **初始颜色映射 (基于主导色)**:
* 遍历 `N x M` 网格
* 对每个单元格,在原图对应区域内找出出现频率最高的**像素 RGB 值 (Dominant Color)**(忽略透明/半透明像素)
* 使用**欧氏距离**在 RGB 空间中,将该主导色映射到**当前选定且未被排除**的调色板 (`activeBeadPalette`) 中最接近的颜色。
* 记录每个单元格的初始映射色号和颜色 (`initialMappedData`)。
3. **平均颜色计算**:
* 在内存中创建一个隐藏的 Canvas (`originalCanvasRef`),并绘制原始图片
* 遍历 `N x M` 网格中的每一个单元格
* 对于每个单元格,计算其在原图上对应的像素区域
* 使用 `originalCtx.getImageData()` 获取该区域内所有像素的 RGBA 数据
* 计算该区域内所有**不完全透明**例如Alpha > 128像素的**平均 RGB 值**。忽略 Alpha 值本身用于颜色距离计算,只关注颜色本身。如果单元格内所有像素都透明,则将其视为默认颜色(如白色 T1
3. **区域颜色合并 (基于相似度)**:
* 使用**广度优先搜索 (BFS)** 遍历 `initialMappedData`
* 识别颜色相似(欧氏距离小于 `similarityThreshold`)的**连通区域**
* 找出每个区域内出现次数最多的**珠子色号**
* 将该区域内所有单元格统一设置为这个主导色号对应的颜色,得到初步平滑结果 (`mergedData`)
4. **颜色映射 (关键步骤)**:
* **调色板**: 项目代码中预先定义了一个 `beadPalette` 数组,包含每个拼豆颜色的 Key (如 "H7")、Hex 值 (如 "#000000") 和预计算的 RGB 值
* **查找最近色**: 对于上一步计算出的每个单元格的平均 RGB 值 (`avgRgb`),调用 `findClosestPaletteColor` 函数
* **距离度量**: 该函数遍历 `beadPalette` 中的所有颜色,使用**欧氏距离**计算 `avgRgb` 与调色板中每个颜色 RGB 值之间的距离:
\[ d = \sqrt{(R_{avg}-R_{palette})^2 + (G_{avg}-G_{palette})^2 + (B_{avg}-B_{palette})^2} \]
* **匹配**: 选择欧氏距离最小的那个调色板颜色作为该单元格的最终映射结果。
* **存储结果**: 将每个单元格匹配到的拼豆 Key 和 Hex 颜色存储在一个二维数组状态 `mappedPixelData` 中。
4. **背景移除 (基于边界填充)**:
* 定义一组背景色号 (`BACKGROUND_COLOR_KEYS`, 如 T1, H1)
* `mergedData` 的**所有边界单元格**开始,使用**洪水填充 (Flood Fill)** 算法
* 标记所有从边界开始、颜色属于 `BACKGROUND_COLOR_KEYS` 且相互连通的单元格为"外部背景" (`isExternal = true`)。
5. **生成预览图**:
* 获取页面上可见的 Canvas (`pixelatedCanvasRef`) 的上下文 `pixelatedCtx`
* 遍历 `mappedPixelData`
* 对于每个单元格,使用其**映射后的拼豆颜色** (`mappedPixelData[j][i].color`) 填充对应的矩形区域
* 在每个填充的色块上绘制**浅灰色细边框**,形成网格线效果
* **注意**: 预览图上不绘制颜色 Key仅显示颜色和网格
5. **颜色排除与重映射**:
* 当用户排除某个颜色 `key` 时:
* 确定一个**重映射目标调色板**:包含网格中**最初存在**的、且**当前未被排除**的所有颜色
* 如果目标调色板为空(表示排除此颜色会导致没有有效颜色可用),则阻止排除
* 否则,将 `mappedPixelData` 中所有使用 `key` 的非外部单元格,重新映射到目标调色板中的**最近似**颜色
* 当用户恢复颜色时,触发完整的图像重新处理流程(步骤 1-4
6. **生成带 Key 的下载图纸 (`handleDownloadImage`)**:
* 用户点击"下载图纸 (带 Key)"按钮时触发
* 动态创建**新的、临时 Canvas** (`downloadCanvas`)
* 定义一个固定的单元格渲染尺寸 `downloadCellSize`(例如 30 像素),确保足够容纳文字
* 设置 `downloadCanvas` 的尺寸为 `(N * downloadCellSize) x (M * downloadCellSize)`
* 获取其上下文 `ctx` 并设置 `ctx.imageSmoothingEnabled = false` 以保证像素块和文字的清晰度。
* 遍历 `mappedPixelData`
* 使用**映射后的拼豆颜色**填充 `downloadCellSize x downloadCellSize` 的背景矩形。
* 绘制**灰色细边框**。
* 使用 `getContrastColor` 函数(基于亮度计算)选择与背景色对比度高的文字颜色(黑色或白色)。
* 在单元格中央绘制对应的**拼豆颜色 Key** (`mappedPixelData[j][i].key`)。
* 使用 `downloadCanvas.toDataURL('image/png')` 生成图片数据并触发下载。
7. **生成 JSON 数据 (`handleDownloadJson`)**:
* 用户点击"下载数据 (JSON)"按钮时触发。
*`mappedPixelData` 提取出一个只包含颜色 Key 的二维数组 `keyGrid`
*`keyGrid` 序列化为格式化的 JSON 字符串。
* 创建 Blob 对象并生成可下载的 `.json` 文件。
6. **生成预览图与下载文件**:
* **预览图**: 在 Canvas 上绘制 `mergedData`,根据 `isExternal` 状态区分内部颜色和外部背景(浅灰),并添加网格线。支持悬停/长按显示色号
* **带 Key 图纸下载**: 创建临时 Canvas,绘制 `mergedData` 中非外部背景的单元格,填充颜色、绘制边框,并在中央标注颜色 Key
* **统计图下载**: 统计 `mergedData` 中非外部背景单元格的各色号数量,生成包含色块、色号、数量的列表式 PNG 图片
### 调色板数据
拼豆的颜色数据定义在 `src/app/page.tsx` 文件顶部的 `beadPaletteData` 对象中。该数据由用户提供,并预处理为包含 Key、Hex 和 RGB 值的 `beadPalette` 数组
**重要**: 调色板数据的准确性直接影响最终的颜色映射结果。请在使用前仔细核对 Key 和 Hex 值。如有需要,可以直接修改 `beadPaletteData` 来添加、删除或修改颜色。
预设的拼豆调色板数据定义在 `src/app/beadPaletteData.json` 文件中。不同的色板组合 (如 168色、96色等) 在 `src/app/page.tsx``paletteOptions` 中定义
## 本地开发
1. 克隆项目:
```bash
git clone <repository-url>
cd perler-beads-generator
git clone https://github.com/Zippland/perler-beads.git
cd perler-beads
```
2. 安装依赖:
```bash
@@ -98,18 +92,15 @@
## 部署
该项目可以轻松部署到 [Vercel](https://vercel.com/) 平台
1. 将代码推送到 GitHub/GitLab/Bitbucket 仓库。
2. 在 Vercel 上导入该 Git 仓库。
3. Vercel 会自动识别 Next.js 项目并进行部署。
该项目可以轻松部署到 [Vercel](https://vercel.com/) 等支持 Next.js 的平台
## 未来可能的改进
* **颜色距离算法**: 使用更符合人类视觉感知的颜色距离算法,如 CIEDE2000 (Delta E),以获得更精确的颜色匹配(但这会显著增加计算复杂度)。
* **性能优化**: 对于超大图片或极高精细度,考虑使用 Web Workers 将图像处理和颜色计算移到后台线程,防止 UI 卡顿
* **调色板管理**: 提供 UI 界面允许用户上传、编辑或选择不同的调色板
* **预览交互**: 在预览图上悬停显示颜色 Key 或统计颜色用量
* **颜色映射算法**: 探索如 K-Means 聚类或使用 CIEDE2000 (Delta E) 颜色距离进行映射,可能获得更优的视觉效果(但计算成本更高)。
* **抖动 (Dithering)**: 添加抖动选项(如 Floyd-Steinberg在有限调色板下模拟更丰富的颜色过渡
* **性能优化**: 对非常大的图片或高粒度设置,考虑使用 Web Workers 进行后台计算
* **用户自定义调色板**: 允许用户上传或创建自己的调色板
* **UI/UX 增强**: 如更直观的区域选择、颜色替换工具等。
## 许可证