Liang Brick Mosaic Generator - Liangdabiao定制的乐高马赛克像素画生成器
English | 中文
项目简介
这是一个100%客户端运行 的开源网络应用,可以将你自己的图片转换成乐高(LEGO)积木马赛克拼贴图,并生成可下载的PDF拼搭说明书或长图说明书。你可以使用现有的乐高Art系列套装来拼搭出完全自定义的马赛克作品。
本应用参考了Christoph Fritzsch开源项目 custombrickmosaic.github.io 进行大量深度定制开发,目前已经达到适应大部分图片生成像素画,还带有功能完全一致的微信小程序版本。用户可以在手机上完成从图片上传到下载说明书的全部流程,所有计算均在客户端完成,图片不会上传到任何服务器。
核心特点:
- 从任意图片生成乐高积木马赛克
- 整个项目所有都是免费,0成本部署一个AI乐高马赛克像素画生成器
- 小程序也是开源免费,功能是一致,用户体验很棒
- 隐私保护:所有计算都在你的浏览器中完成,图片不会上传到任何服务器
- 自动生成带分区指导的PDF拼搭说明书 和长图说明书
- 支持组合多个乐高Art系列套装来获得更大尺寸的马赛克
- 支持自定义裁剪:可自由框选图片区域,自动保持马赛克宽高比
- 支持AI 风格优化:对接火山引擎即梦 AI,一键将图片转为多边形艺术风格,提升马赛克效果
- 支持图片裁切、色彩调整等预处理(色相、饱和度、明度、对比度、暗部、亮部)
- 完全免费开源
特别感谢佬友支持: linux.do

AI一键优化:


小程序:

目录
- 工作原理
- 详细操作步骤
- 界面功能详解
- 支持的乐高Art套装
- 使用技巧
- [AI 风格优化](#AI 风格优化)
- 本地运行
- [部署到 Cloudflare Pages](#部署到 Cloudflare Pages)
- 技术架构
- 数据隐私
- 更新日志
工作原理
整体流程
用户上传图片 → 图片预处理(裁剪/缩放/调色)→ 算法分配积木 → 生成预览 → 生成PDF/长图说明书
核心算法
整个马赛克生成分为两个阶段:
第一阶段:初始分配
- 调整尺寸:将输入图片重新缩放至马赛克目标尺寸(宽 × 高 颗粒度)
- 添加噪声:在原始颜色值中加入微小随机噪声,以打破颜色相等的情况,避免算法卡住
- 颜色匹配 :将每个像素的颜色与你选择的乐高套装中所有可用颜色进行比较,计算颜色距离(RGB空间中的平方欧氏距离)
- 贪心分配:按像素逐个分配最匹配的可用颜色,每分配一个颗粒,对应颜色的可用数量减1。如果最佳颜色已用完,则选择下一个最佳匹配颜色
作者测试过多种颜色空间(如CIE LAB),发现RGB空间已经能获得很好的效果。CIE LAB版本代码目前保留但被注释掉了。
第二阶段:优化交换
初始分配完成后,算法进入优化阶段:
- 迭代尝试交换两个不同像素之间的积木颗粒
- 如果交换后总体颜色匹配度变好(总色差更小),则保留交换
- 重复这个过程,直到无法再通过交换改善结果
- 这个"暴力"交换过程能显著提升最终效果,但对于大尺寸马赛克需要较长计算时间
颜色匹配原理
颜色距离计算公式(RGB空间):
distance = (r1 - r2)² + (g1 - g2)² + (b1 - b2)²
distance越小,颜色越接近。
详细操作步骤
步骤1:选择源图片
- 点击"1. 选择源图片"下的文件选择框
- 从你的电脑或手机中选择一张图片
- 图片加载后会显示预览缩略图
- 选择裁切方式:
- 裁切中心:保持原图宽高比,只裁切中心区域
- 缩放适应:将整张图拉伸/缩放到目标尺寸
- 自定义裁切:打开裁剪工具,自由框选所需区域(自动保持马赛克宽高比)
- (可选)勾选"忽略图片中的黑色区域"
- (可选)使用颜色调整滑块微调图片效果
步骤2:选择马赛克尺寸
- 通过加减按钮调整马赛克的宽度和高度(单位:乐高颗粒/studs)
- 查看下方显示的所需颗粒数量
- 一个标准乐高Art套装是48×48=2304颗粒
步骤3:选择你拥有的乐高Art套装
- 在列表中找到你拥有的套装,通过加减按钮设置你要使用的数量
- 每个套装包含不同的颜色和颗粒数量,程序会自动计算总可用颗粒
- 查看下方显示的总可用颗粒数
- 注意:必须保证可用颗粒数 ≥ 所需颗粒数,才能进行计算
步骤4:计算马赛克
- 点击"计算马赛克"按钮开始计算
- 进度条会显示计算进度
- 等待计算完成,右侧会显示马赛克预览图
步骤5:下载说明书
计算完成后,提供两种下载格式:
- PDF格式:点击"下载拼搭说明书 (PDF)",生成标准PDF文件
- 长图格式:点击"下载说明书长图 (PNG)",生成一张包含全部说明内容的长图,适合手机查看或社交分享
界面功能详解
左侧控制面板
第一部分:选择源图片(Step 1)
裁切/缩放按钮组
[裁切中心] [缩放适应] [自定义裁切]
- 裁切中心:保持原图宽高比,只裁切中心区域适应目标尺寸
- 缩放适应:将整张图拉伸/缩放到目标尺寸,可能会改变宽高比
- 自定义裁切 :打开交互式裁剪弹窗,自由拖动选择裁剪区域
- 裁剪框自动保持马赛克的宽高比(宽度:高度)
- 支持拖动移动选区、缩放图片、调整裁剪框大小
- 裁剪完成后自动更新预览并重新计算
忽略黑色区域复选框
- 勾选后:RGB值为(0,0,0)的纯黑色区域不会被分配积木,在说明书中用"?"标记
- 默认:勾选
AI 风格优化按钮
- 点击"AI 风格优化"按钮,将当前图片发送到后端 AI 服务进行风格化处理
- 使用火山引擎即梦 AI,将图片转换为多边形艺术风格(锐利线条、现代图形感)
- 处理时间约 10-30 秒,完成后自动替换图片并刷新预览
- 可多次点击"重新AI优化"进行迭代优化
- 注意:此功能需要部署到 Cloudflare Pages 才能使用(依赖后端 API)
颜色调整滑块
| 滑块 | 范围 | 功能 |
|---|---|---|
| 暗部 (Shadows) | -100 ~ +100 | 调整暗部亮度曲线 |
| 亮部 (Highlights) | -100 ~ +100 | 调整亮部亮度曲线 |
| 色相 (Hue) | -180 ~ +180 | 整体颜色偏移 |
| 饱和度 (Saturation) | -100 ~ +100 | 色彩饱和度调整 |
| 明度 (Value) | -100 ~ +100 | 整体亮度调整 |
| 对比度 (Contrast) | -100 ~ +100 | 明暗对比度调整 |
第二部分:选择马赛克尺寸(Step 2)
- 通过加减按钮或直接输入调整宽度和高度(16~200)
- 下方实时显示所需颗粒数量
第三部分:选择拥有的乐高Art套装(Step 3)
每个套装可输入小数(如0.5),用于限制颜色数量以获得更具艺术感的效果。详见颗粒限制技巧。
第四部分:运行计算(Step 4)
点击"计算马赛克"按钮,进度条分为初始分配和优化交换两个阶段。
第五步:下载说明书(Step 5)
两种下载格式:
- 下载拼搭说明书 (PDF):标准PDF文件,每页一个16×16分区
- 下载说明书长图 (PNG):所有页面纵向拼接的长图(2倍清晰度),适合手机查看和分享
右侧预览区
- 马赛克预览:计算完成后显示生成的马赛克预览图
- 颜色调整:提供6个滑块实时调整图片颜色参数
支持的乐高Art套装
程序内置了以下11款乐高Art系列套装的颜色和颗粒数据:
| 序号 | 套装名称 | 产品编号 | 标准尺寸 | 颗粒总数 |
|---|---|---|---|---|
| 1 | The Beatles | 31198 | 48×48 | 2304 |
| 2 | Marilyn Monroe | 31197 | 48×48 | 2304 |
| 3 | Iron Man | 31199 | 48×48 | 2304 |
| 4 | The Sith | 31200 | 48×48 | 2304 |
| 5 | Hogwarts | 31201 | 48×48 | 2304 |
| 6 | Mickey Mouse | 31202 | 48×48 | 2304 |
| 7 | Personalized Portrait | 41958 | 48×48 | 2304 |
| 8 | World Map | 31203 | 48×192 | 约9216 |
| 9 | Art Project | 21226 | 48×48 | 2304 |
| 10 | Elvis Presley | 31204 | 48×48 | 2304 |
| 11 | Batman | 31205 | 48×48 | 2304 |
组合示例:
- 1个套装:48×48
- 2个套装:64×64(需要 4096颗粒)
- 4个套装:96×96(需要 9216颗粒)
- 世界地图套装:可以做48×192的长条横幅马赛克
使用技巧
输入图片选择
- 好的对比度是获得好结果的关键
- 选择颜色分布与你拥有的套装相近的图片
- 尝试不同的裁切方式,多试几张
- 均匀纯色背景效果更好,可以先用图像处理软件将背景换成纯色
自定义裁剪技巧
- 使用自定义裁剪可以精确选择图片中你想要的区域
- 裁剪框会自动保持与马赛克相同的宽高比
- 建议先调整好马赛克的目标宽高比,再进行裁剪,这样裁剪框比例与最终结果一致
颜色调整技巧
- 多试不同滑块组合,看看调整后对结果的影响
- 使用色相滑块让整体颜色更接近乐高现有颜色
- 有时降低饱和度能获得更好效果
- 利用暗部/亮部滑块可以精细控制图片的明暗分布
- 如果图片背景占很大空间,先用外部软件将背景设为纯黑,然后勾选"忽略黑色区域"
颗粒限制的艺术效果
- 刻意限制颗粒数量能获得更有艺术感的结果
- 限制颗粒数量会迫使算法使用次优颜色,反而增加了马赛克的色彩空间
- 技巧:输入小数如0.9来进一步限制每种颜色可用数量
AI 风格优化
AI 风格优化功能通过对接火山引擎即梦 AI,将用户上传的图片一键转换为更适合乐高马赛克的艺术风格。
风格效果
- 纯黑色背景
- 戏剧性低光
- 多边形艺术风格,锐利的线条和刻面,现代图形感
- 动态构图,融合写实与抽象
工作原理
用户点击"AI 风格优化"
↓
前端将 canvas 图片转为 JPEG base64
↓
POST 到 /api/ai-optimize(Cloudflare Pages Function)
↓
后端调用火山引擎即梦 AI API(签名认证 + 异步任务)
↓
轮询等待 AI 处理完成(最长约3分钟)
↓
返回优化后的图片 URL/base64
↓
前端替换图片、刷新预览,如已生成马赛克则自动重新计算
后端 API
- 路径:
/api/ai-optimize - 方法:
POST - 请求体:
{ "imageBase64": "data:image/jpeg;base64,...", "prompt": "风格描述" } - 返回:
{ "success": true, "imageUrl": "..." }
环境变量
后端 API 需要配置以下环境变量(在 Cloudflare Pages Settings → Environment variables 中设置):
| 变量名 | 说明 |
|---|---|
VOLC_ACCESS_KEY_ID |
火山引擎 Access Key ID |
VOLC_SECRET_ACCESS_KEY |
火山引擎 Secret Access Key |
本地运行
本项目是纯静态HTML+JavaScript应用,无需构建过程,无需任何依赖。
方法一:直接打开
用浏览器直接打开 index.html 即可使用。
方法二:使用本地HTTP服务器
bash
python -m http.server 8000
# 然后访问 http://localhost:8000
bash
npx serve .
依赖项
所有依赖都通过CDN加载:
- Bootstrap 5.0.0-beta2(CSS + JS)
- jsPDF 1.5.3(PDF生成)
- Cropper.js 1.6.2(图片裁剪)
无需npm install,无需任何构建工具。
部署到 Cloudflare Pages
本项目包含 Cloudflare Pages Function(functions/api/),因此不能使用 Cloudflare 后台的直接拖拽上传(拖拽上传不支持 Functions),必须使用 wrangler CLI 部署。
前提条件
- 安装 Node.js(18+)
- 在 Cloudflare Dashboard 创建 Pages 项目
- 准备好火山引擎的 Access Key(用于 AI 风格优化功能)
部署步骤
1. 安装 wrangler 并登录
bash
npm install -g wrangler
wrangler login
登录后会自动打开浏览器进行授权。
2. 配置环境变量
在 Cloudflare 后台 Pages → 你的项目 → Settings → Environment variables 中添加:
| 变量名 | 值 |
|---|---|
VOLC_ACCESS_KEY_ID |
你的火山引擎 AK |
VOLC_SECRET_ACCESS_KEY |
你的火山引擎 SK |
3. 部署
bash
# 部署到已有项目
npx wrangler pages deploy . --project-name=你的项目名
# 或部署到新项目
npx wrangler pages deploy .
部署完成后会输出访问 URL。
项目文件结构(含 Cloudflare)
/
├── index.html # 主页面
├── brickMosaic.js # 前端逻辑
├── cf_about.png # 头像
├── favicon.ico # 图标
├── LICENSE # MIT 许可证
├── package.json # wrangler 部署脚本
├── wrangler.toml # Cloudflare 配置
└── functions/
└── api/
└── ai-optimize.js # AI 优化 API(Pages Function)
注意事项
- 不要使用 Cloudflare 后台的拖拽上传 ,它不会处理
functions/目录,会导致 API 返回 405 - 可以通过 Git 集成部署(Cloudflare Pages 关联 GitHub 仓库),推送代码后自动部署,这也支持 Functions
- 本地开发测试可用
npx wrangler pages dev .,会自动启动本地服务器并支持 Functions 调用
项目文件结构
/
├── index.html # 主HTML页面,包含UI布局
├── brickMosaic.js # 全部应用逻辑
├── cf_about.png # About页面作者头像
├── favicon.ico # 网站图标
└── LICENSE # MIT许可证
技术架构
- 语言:原生JavaScript (ES6+)
- 图像处理:HTML5 Canvas API
- 样式框架:Bootstrap 5(CDN)
- PDF生成:jsPDF 1.5.3(CDN)
- 图片裁剪:Cropper.js 1.6.2(CDN)
- 长图生成:Canvas API + toDataURL()
- 部署:GitHub Pages 静态托管
- 计算:马赛克生成在浏览器客户端完成;AI 优化通过 Cloudflare Pages Function 调用火山引擎 API
主要函数说明
| 函数 | 功能 |
|---|---|
init() |
初始化UI状态和事件处理器 |
rgb2hsv() / hsv2rgb() |
RGB转HSV色彩空间互相转换 |
adjustImageHSV() |
应用色相、饱和度、明度调整 |
adjustImageContrast() |
应用对比度调整 |
adjustImageCurves() |
应用暗部/亮部曲线调整 |
rgb2lab() / lab2rgb() / deltaE() |
RGB转CIE LAB,计算DeltaE色差(已注释) |
getPartListOfOneSet() |
获取指定套装的所有颜色和数量数据 |
updatePartList() |
根据用户选择更新总可用零件列表 |
drawPreviewImage() |
绘制预览缩略图(支持自定义裁剪) |
generateValidColoring() |
核心两阶段生成算法 |
drawMosaic() |
在画布上绘制马赛克预览 |
openCustomCropModal() |
打开自定义裁剪弹窗 |
confirmCustomCrop() |
确认裁剪并应用 |
generateInstructions() |
生成PDF说明书 |
generatePDFTitlePage() |
生成PDF标题页(马赛克预览+色块图例) |
generatePDFSectionPage() |
生成PDF分区指导页(16×16网格) |
generateInstructionsImage() |
生成长图说明书(PNG) |
generateImageTitlePage() |
生成长图标题页(Canvas渲染) |
generateImageSectionPage() |
生成长图分区页(Canvas渲染) |
小程序像素画说明书原理
● 说明书长图生成原理
整体架构
用户点击"下载说明书"
↓
generateImage()
↓
创建一张超高的离屏Canvas(宽度固定,高度 = 页数 × 单页高度)
↓
逐页绘制:
├─ 第1页:标题页(总览)
├─ 第2页:分区1(左上角16×16)
├─ 第3页:分区2(第2列16×16)
├─ ...
└─ 第N页:最后一个分区
↓
wx.canvasToTempFilePath() 导出为一张PNG长图
↓
wx.previewImage() 预览 / wx.saveImageToPhotosAlbum() 保存到相册
关键参数
SCALE = 4 // 1mm = 4px(手机屏幕适配)
PAGE_W = 210×4 = 840px // A4纸宽度
PAGE_H = 297×4 = 1188px // A4纸高度
SECTION_SIZE = 16 // 每个分区16×16颗粒
以 48×48 马赛克为例:
- 分区数 = ceil(48/16) × ceil(48/16) = 3×3 = 9个分区
- 总页数 = 1(标题页)+ 9(分区页)= 10页
- 长图总高度 = 1188 × 10 = 11880px
第1页:标题页 (renderTitlePage)
┌─────────────────────────────────┐
│ Custom Brick Mosaic │
│ Source: mosaic │
│ Resolution: 48 x 48 (3x3) │
│ │
│ ┌─────────────────────────┐ │
│ │ │ │
│ │ 整个马赛克缩略预览 │ │ 每个颗粒画一个彩色小方块
│ │ 带分区网格线 │ │ 网格线将图分成16×16的区域
│ │ 每个区域标序号 │ │ 每个区域中心写编号 1-9
│ │ │ │
│ └─────────────────────────┘ │
│ │
│ ┌─────────┐ │
│ │ 颜色图例 │ │ 每种实际用到的颜色:
│ │ ●1 150x │ │ 圆形/方形(取决于积木类型)
│ │ ●2 230x │ │ 内圈编号
│ │ ■3 180x │ │ 数量统计
│ │ ... │ │
│ └─────────┘ │
│ │
│ github.com/liangdabiao │
│ Page 1 / 10 │
└─────────────────────────────────┘
标题页做了这些事:
1. 绘制马赛克总览 --- 遍历 finalMosaicIm[x][y],每个颗粒画一个 brickW × brickH 的彩色方块
2. 绘制分区网格 --- 白色半透明线将图分成 16×16 的区域,每个区域中心写编号
3. 统计颜色用量 --- 遍历所有颗粒,按 im[x][y][3](颜色索引)统计每种颜色出现次数
4. 绘制颜色图例 --- 为每种颜色画圆形(圆钉)或方形(板),内圈写编号,旁边写数量×
5. 颗粒类型区分 --- im[x][y][4] 决定形状:3024=方形板,6141=圆钉,其他=普通圆形
第2~N页:分区页 (renderSectionPage)
┌─────────────────────────────────┐
│ Section 3 │
│ │
│ ┌─────────────────────────┐ │
│ │ ■ ■ ● ■ ■ ● ■ ■ ● ■ ■ │ │
│ │ ■ ● ■ ■ ● ■ ● ■ ● ■ ■ │ │ 16×16网格
│ │ ● ■ ■ ● ■ ● ■ ● ■ ■ ■ │ │ 每个位置画一个积木颗粒
│ │ ■ ■ ● ■ ■ ● ■ ● ■ ● ■ │ │ 黑色背景+彩色圆形/方形
│ │ ... │ │ 颗粒中心写颜色编号
│ │ ■ ● ■ ■ ● ■ ● ■ ● ■ ■ │ │
│ └─────────────────────────┘ │
│ │
│ github.com/liangdabiao │
│ Page 4 / 10 │
└─────────────────────────────────┘
分区页做了这些事:
1. 计算当前分区对应的马赛克区域 --- 例如 Section 3(编号从0开始是2),对应第1列第0行的16×16区域
xOffset = sectionNumber % numSectionsX * 16 // 水平偏移
yOffset = floor(sectionNumber / numSectionsX) * 16 // 垂直偏移
2. 在黑色背景上画网格 --- 每个格子中心画积木颗粒
3. 颗粒大小 --- gridSize / 16 / 2 作为半径,尽量占满页面
4. 颗粒上写编号 --- 与标题页图例中的编号对应,方便用户找颗粒
数据来源
所有数据来自 _finalMosaicIm,这是算法 generateValidColoring() 的输出:
im[x][y] = [R, G, B, colorIndex, partType, elementId]
// R, G, B: 匹配到的乐高颜色RGB值
// colorIndex: 在fullPartList中的索引
// partType: 积木类型(6141=圆钉, 3024=方形板, 3=忽略)
// elementId: 乐高官方零件编号
对比网页版的差异
┌──────────┬───────────────┬─────────────────────┐
│ 维度 │ 网页版 │ 小程序版 │
├──────────┼───────────────┼─────────────────────┤
│ 输出格式 │ PDF (jsPDF) │ PNG长图 │
├──────────┼───────────────┼─────────────────────┤
│ 渲染方式 │ jsPDF绘图命令 │ Canvas 2D绑定 │
├──────────┼───────────────┼─────────────────────┤
│ 分辨率 │ 1mm=6px │ 1mm=4px(手机适配) │
├──────────┼───────────────┼─────────────────────┤
│ 保存方式 │ 浏览器下载 │ 预览+保存到相册 │
├──────────┼───────────────┼─────────────────────┤
│ 历史记录 │ 无 │ 本地存储最近20条 │
└──────────┴───────────────┴─────────────────────┘
核心渲染逻辑(标题页布局、分区页网格、颜色图例)与网页版完全一致,只是从 jsPDF API 翻译成了 Canvas 2D API。
数据隐私
算法完全在你的浏览器中运行,所有计算都在你的本地机器上完成。不需要将数据上传到任何服务器,数据隐私得到保证。
你可以断网使用,图片永远不会离开你的设备。
更新日志
AI 风格优化
- 新增"AI 风格优化"按钮,对接火山引擎即梦 AI API
- 一键将图片转换为多边形艺术风格(纯黑背景、戏剧性低光、锐利刻面线条)
- 通过 Cloudflare Pages Function 实现后端 API(
/api/ai-optimize) - 支持火山引擎 HMAC-SHA256 签名认证
- 异步任务提交 + 轮询机制,最长等待约3分钟
- 优化完成后自动刷新预览,如已生成马赛克则自动重新计算
- 图片安全检测失败时给出友好提示
自定义裁剪功能
- 集成 Cropper.js 1.6.2,新增"自定义裁切"按钮
- 裁剪弹窗自动保持马赛克宽高比
- 等待弹窗完全展开后再初始化裁剪器,避免容器尺寸为0的问题
- 裁剪结果正确传递到马赛克生成和"忽略黑色区域"检测
说明书长图下载
- 新增"下载说明书长图 (PNG)"按钮
- 内容与PDF完全一致:标题页(马赛克预览+色块图例)+ 分区指导页(16×16编号网格)
- 使用Canvas API渲染,1mm = 6px(2倍清晰度)
- 所有页面纵向拼接为一张长图,适合手机查看和社交分享
- PDF和长图共享进度条和状态管理
颜色调整增强
- 新增"暗部"和"亮部"曲线调整滑块
- 支持对图片暗部和亮部分别进行精细控制
Bug 修复
- 修复自定义裁剪 + "忽略黑色区域"组合使用时,黑色检测使用了原图而非裁剪后的图像,导致马赛克出现大量空白区域的问题
- 修复裁剪弹窗在 Bootstrap 5.0.0-beta2 中的兼容性问题(
getOrCreateInstance不存在,改用getInstance+new)
其他类似项目
许可证
MIT License - 详见 <LICENSE> 文件。
源代码
https://github.com/liangdabiao
欢迎提交Issue和Pull Request。