手绘拼豆图纸?我选择Python!
前言 最近我老婆迷上了拼豆。 什么是拼豆? 拼豆就是将各种颜色的小豆子拼在一起,通过熨烫成塑料画,在现实中实现各种像素画。 放一张我老婆给我做的拼豆为例,就很容易理解了: ! (https://api.flowersink.com/uploads/blog/images/compressed 1743401100136
前言
最近我老婆迷上了拼豆。
什么是拼豆?拼豆就是将各种颜色的小豆子拼在一起,通过熨烫成塑料画,在现实中实现各种像素画。
放一张我老婆给我做的拼豆为例,就很容易理解了:

当然,拼豆和编程、技术很难关联在一起,为什么会诞生这篇博客呢,还需要再讲讲拼豆中最重要的东西:图纸
拼豆的图纸
拼豆是像素画,是由一个一个的豆子(像素)拼起来的。
拼豆过程是用镊子将一个个极小的颗粒按像素画的布局进行摆放,所以不可能在拼豆的过程中进行绘制,那就需要提前获取图纸,用来作为拼豆的参考。
而给拼豆的玩家一张像素画,它就可以按照像素画一颗一颗豆的拼出来了吗?并不是的
我们以经典像素画风游戏Minecraft中的胡萝卜为例,它的原画是这样的:

在拼豆中,面对这样的原画/像素画,颜色虽然有上百种,但也是完全提前固定好的颜色,不像现实绘画可以自由调色,并且还存在以下问题:
1.这张画需要什么颜色的豆子?每种颜色需要多少豆子?
2.这张画的尺寸是多大?如果超过50*50那就无法单用一个画板进行绘制了。
3.没有参考线,一旦画错,所付出的成本是很大的。
那么胡萝卜的图纸是怎么样的呢,请看下图:

所以,只要有图纸,拼豆玩家就可以通过图纸所需要的豆子颜色、豆子数量、大小进行提前准备(毕竟拼豆全颜色一套下来要接近1000+RMB!)
然而网络上图纸的资源并不多,尤其是我和我老婆很喜欢的Minecraft图纸,几乎没有资源。如何获取图纸成为了最大的难题。
获取图纸
获取图纸的第一步是获取Minecraft中各类物品的原图原画。
如果想要获取MC的物品原图,有一个笨方法就是去游戏里一个一个截,当然如果我采用这种笨方法就不会有这篇博客了……
我在逛Minecraft WIKI的时候,突然想到了爬虫。
编写爬虫
从网络中可以得知,Minecraft的维基百科API为https://minecraft.fandom.com/api.php
于是我们可以很轻易的通过API去抓取我们所需要的所有物品原画,先定义一些基础信息,例如安装库、API地址、保存路径、抓取类别和正则表达式:
import os
import requests
import re
# Minecraft 维基百科 API
WIKI_API_URL = "https://minecraft.fandom.com/api.php"
# 本地保存路径
SAVE_DIR = "minecraft_items"
os.makedirs(SAVE_DIR, exist_ok=True)
# 需要抓取的物品类别
CATEGORIES = [
"Items", "Blocks", "Tools", "Weapons", "Armor", "Food", "Brewing", "Materials"
]
# 过滤非法字符的正则
INVALID_FILENAME_CHARS = r'[<>:"/\\|?*]'
def sanitize_filename(filename):
"""移除 Windows 文件名中的非法字符"""
return re.sub(INVALID_FILENAME_CHARS, "", filename)
先获取所有物品
def get_items_from_category(category):
""" 获取指定类别下的所有物品 """
item_list = []
params = {
"action": "query",
"format": "json",
"list": "categorymembers",
"cmtitle": f"Category:{category}",
"cmlimit": "max"
}
while True:
response = requests.get(WIKI_API_URL, params=params)
data = response.json()
items = data.get("query", {}).get("categorymembers", [])
item_list.extend([item["title"] for item in items])
# 处理分页情况,若 API 返回 "continue",则继续请求下一页数据
if "continue" in data:
params.update(data["continue"])
else:
break
return item_list
获取物品的图片和分类(方便按文件夹文类保存)
def get_item_image_and_category(item_name):
""" 获取物品的图片 URL 和分类 """
params = {
"action": "query",
"format": "json",
"prop": "pageimages|categories",
"titles": item_name,
"piprop": "original"
}
response = requests.get(WIKI_API_URL, params=params)
data = response.json()
pages = data.get("query", {}).get("pages", {})
image_url = None
categories = []
for page in pages.values():
if "original" in page:
image_url = page["original"]["source"] # 提取图片 URL
if "categories" in page:
categories = [cat["title"].replace("Category:", "") for cat in page["categories"]] # 获取物品所属分类
return image_url, categories
编写主函数,将图片下载到本地并分类、在命令行中展示结果
def download_image(url, item_name, category):
""" 下载图片并按类别保存,避免重复下载 """
if not url:
print(f"[跳过] {item_name} 没有找到图片")
return
# 处理非法字符
safe_item_name = sanitize_filename(item_name)
# 确保分类文件夹存在
category_dir = os.path.join(SAVE_DIR, category)
os.makedirs(category_dir, exist_ok=True)
# 目标文件路径
filename = os.path.join(category_dir, f"{safe_item_name}.png")
# **跳过已下载文件**
if os.path.exists(filename):
print(f"[已存在] {safe_item_name} (分类: {category}),跳过下载")
return
# 下载图片
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(filename, "wb") as file:
for chunk in response.iter_content(1024):
file.write(chunk)
print(f"[成功] {safe_item_name} 下载完成 (分类: {category})")
else:
print(f"[失败] 无法下载 {safe_item_name}")
if __name__ == "__main__":
all_items = {}
for category in CATEGORIES:
items = get_items_from_category(category)
print(f"在 {category} 分类下找到 {len(items)} 个物品")
for item in items:
all_items[item] = category # 记录物品所属类别
print(f"总共找到 {len(all_items)} 个物品")
for item, category in all_items.items():
image_url, item_categories = get_item_image_and_category(item)
# 选取最匹配的分类,优先使用物品自身的分类,否则使用默认分类
best_category = next((cat for cat in item_categories if cat in CATEGORIES), category)
download_image(image_url, item, best_category)
启动py程序,便开始抓取WIKI中的所有图片了

生成图纸
获取所有原画后,下一步就是生成图纸了。
拼豆圈有一个免费开源工具:拼豆辅助工具(如果没有的话我其实还打算开发一个来着……)
我先通过图片尺寸修改工具将所有原图批量修改为16*16尺寸,再手动一张一张通过拼豆辅助工具生成图纸(工具没有批量功能……)
但此时又带来了一个新的问题,图纸没有相应的豆子颜色数量统计。
统计豆子颜色数量
因为拼豆辅助工具在生成图纸后自带颜色统计,通过复制可以得到以下文本:
合计 142
H7 40
B15 23
B8 16
F10 14
F13 8
A10 8
H16 7
F6 7
A7 6
F11 5
A18 2
B23 2
G20 1
F18 1
G5 1
A14 1
于是我想到了将文件名命名为颜色数量统计的方法,那么就需要编写一个程序,将文本转化为无换行且更易读的字符串。
用html+css+js即可简单实现,当我将文本粘贴到输入框中,会自动生成字符串并写入我的剪切板
这就是完全不想多操作一步的懒再花!
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据转换</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
textarea {
width: 100%;
height: 100px;
font-size: 16px;
}
#output {
margin-top: 20px;
font-size: 18px;
color: green;
font-weight: bold;
}
</style>
</head>
<body>
<h2>粘贴数据并自动转换</h2>
<textarea id="inputArea" placeholder="在此粘贴数据..."></textarea>
<div id="output"></div>
<script>
document.getElementById("inputArea").addEventListener("paste", function (event) {
setTimeout(() => {
let inputText = event.target.value;
let lines = inputText.split(/\r?\n/);
let result = [];
lines.forEach(line => {
let parts = line.trim().split(/\s+/);
if (parts.length >= 2) {
let key = parts[0];
let value = parts[1];
result.push(`${key}=${value}`);
}
});
let outputText = result.join(","); // 使用中文逗号
outputText += '.png'
document.getElementById("output").textContent = outputText;
// 复制到剪贴板
navigator.clipboard.writeText(outputText).then(() => {
console.log("已复制到剪贴板:", outputText);
}).catch(err => {
console.error("复制失败:", err);
});
}, 100); // 延迟获取粘贴内容
});
</script>
</body>
</html>
最终效果如图

一共100张有效原图,最终进行100次操作生成了这样100张Minecraft图纸

虽然因为像素原画的限制,图纸略微有一些细节上的不足,但终归是达成了自己的需求,总的来说也是一次非常有趣的经历,真是技术改变生活啊!