img2points
v1.0.0
Published
Turn a photo into deterministic pointillism or bead-art SVG. Pixel colors come from the image; code generates points and renders.
Maintainers
Readme
img2points 不是一次性的图片滤镜,而是一条可保存、可审计、可重放的视觉编译管线。
它将 PNG/JPEG 编译为稳定的 Visual Point IR,再交给不同渲染器输出点彩、拼豆、PNG 或交互式 HTML。
为什么选择 img2points
传统的“图片转点阵”脚本往往把采样、随机布局和最终样式绑死在一次渲染里:换尺寸、换材质、换输出格式都要重新读图,结果也难以精确复现。img2points 用确定性 seed 与渲染无关的 Point IR 解开这层耦合,让一次采样成为可持续复用的视觉资产。
| 核心能力 | 带来的价值 | | ---------------------------------- | ----------------------------------------------------------------------------------------------- | | Deterministic by design | 相同输入、配置、版本与 seed 生成相同 Point JSON,适合版本管理、自动化流水线与视觉回归。 | | Visual Point IR | 将归一化坐标、像素颜色、深度与形状保存为独立数据;IR 生成后,重渲染不再读取原图。 | | Image-faithful sampling | 直接从 PNG/JPEG 采样颜色,并结合局部边缘信息组织点位,不依赖提示词猜测画面。 | | 规则拼豆网格 | 采样阶段从图片生成规则方珠网格,颜色取格子中心像素;不均色、不吸附色板、不在渲染阶段池化。 | | Multi-output toolchain | 同一条命令可产出 SVG、PNG、Point JSON 与交互透镜页,并提供 inspect、validate、viewer 调试工具。 | | Renderer-oriented architecture | 采样与渲染职责分离,内置 SVG 渲染路径消费 IR,也支持通过 registry 接入自定义 renderer。 | | Schema-backed data contract | 提供 Visual IR Schema,便于理解格式并建设上层工具。 |
项目一览
| 维度 | 当前能力 |
| -------- | ----------------------------------------------- |
| 输入 | PNG、JPEG、Visual Point IR、SVG |
| 采样布局 | scatter 自然散点、bead 规则拼豆网格 |
| 核心外观 | default、dot、bead |
| 渲染器 | 核心 SVG renderer |
| 输出 | SVG、PNG、Point JSON、交互式 HTML、Debug Viewer |
| 可复现性 | Seeded sampling + stable normalized IR |
| 运行环境 | Node.js 20+ / TypeScript 5.x |
效果展示
同一张照片、同一个 seed,通过不同的采样与渲染策略得到两种视觉语言。
快速开始
1. 安装
需要 Node.js 20+。
npm install -g img2points从源码安装:
git clone https://github.com/endlessYoung/img2points.git
cd img2points
npm ci2. 照片 → 点彩 SVG / PNG / Point IR
npx img2points \
--image examples/portrait-reference.png \
--layout scatter \
--preset dot \
--seed 42 \
--points out/portrait-points.json \
--out out/portrait-dot.svg \
--png out/portrait-dot.png这一步会把采样结果保存为 out/portrait-points.json。之后可以脱离原图继续创作。
3. 同一份 IR → 另一种视觉风格
# 不重新读取图片,直接换成圆角方珠外观
npx img2points \
--from-points out/portrait-points.json \
--preset bead \
--width 1600 \
--out out/portrait-square-beads.svg4. 照片 → 规则拼豆网格
npx img2points \
--image examples/portrait-reference.png \
--layout bead \
--preset bead \
--seed 42 \
--target-points 6400 \
--points out/bead-grid.json \
--out out/bead-grid.svg \
--png out/bead-grid.png建议始终显式写出
--layout bead --preset bead。仅使用--preset bead隐式选择 bead layout 是兼容行为,后续版本将移除。
架构
架构中心不是 SVG,而是 Visual Point IR:Sampler 负责生成点,Renderer 只消费点。图片颜色一旦写入 IR,后续切换尺寸、外观或渲染器都不再回读图片。
两层控制面:Layout ≠ Preset
| 控制面 | 所属阶段 | 负责什么 | 可选值 |
| ---------- | ------------- | -------------------------------- | -------------------------- |
| --layout | Sampling | 点如何铺设、颜色如何写入 IR | scatter / bead |
| --preset | SVG Rendering | 核心 SVG renderer 如何绘制每个点 | default / dot / bead |
--layout bead --preset bead:采样阶段建立规则网格、读取格子中心像素色(不均色、不吸附色板、不池化);SVG renderer 将每个 IR 点画成圆角方珠。
Visual Point IR 中间表示
Visual Point IR 是采样器与渲染器之间的稳定契约。坐标、尺寸和重要性均采用归一化表示,因此输出分辨率可以变化,而构图无需重算。
{
"version": "1.0",
"canvas": {
"width": 800,
"height": 800,
"background": "#F4EFE6"
},
"seed": 42,
"points": [
{
"id": "p0",
"x": 0.46,
"y": 0.38,
"color": "#E4A45A",
"size": 0.018,
"opacity": 0.96,
"style": {
"shape": "circle",
"rotation": 6,
"depth": 0.78
}
}
],
"meta": {
"layout": "scatter",
"colorSource": "pixel",
"generator": "[email protected]"
}
}IR 带来的直接收益:
- 可复现:相同输入、选项、实现版本与 seed 得到相同 Point JSON。
- 可移植:Renderer 不依赖原图。
- 可重绘:同一份数据可切换尺寸、preset、背景与 renderer。
- 可检查:点位可携带
layer、importance与自定义 metadata。 - 向后兼容:读取旧版 flat Point JSON 时会自动提升为 canonical Visual IR。
完整格式见 schema/visual-ir.schema.json 与 examples/visual-ir.json。
输出管线
| 输出 | 参数 | 适合场景 |
| ---------------- | ---------- | ----------------------------------------- |
| SVG | --out | Web、设计工具、矢量资产与后续编辑 |
| PNG | --png | 社交媒体、预览图、位图交付 |
| Point JSON | --points | 缓存采样、版本管理、二次渲染与程序化处理 |
| Interactive HTML | --html | 鼠标附近点位局部放大的展示页 |
| Debug Viewer | --viewer | 缩放、拖拽、layer / region 筛选与采样排查 |
# SVG → PNG
npx img2points \
--from-svg out/portrait-dot.svg \
--png out/portrait-dot.png \
--width 1600
# 检查、校验与可视化 Point IR
npx img2points --inspect out/portrait-points.json
npx img2points --validate out/portrait-points.json
npx img2points \
--from-points out/portrait-points.json \
--viewer out/portrait-debug.htmlCLI 参考
npx img2points --help| 参数 | 说明 |
| ---------------------------------- | ------------------------------------------------------------------------- |
| --image <file> | 读取 PNG/JPEG,并从像素采样颜色与局部边缘 |
| --from-points <file> | 从已有 Visual Point IR 重渲染,不再读取图片 |
| --from-svg <file> | 将已有 SVG 转成 PNG,需同时提供 --png |
| --layout scatter\|bead | 图片采样布局;建议始终显式指定 |
| --preset default\|dot\|bead | 核心 SVG renderer 的外观 |
| --seed <n> | 确定性随机 seed;默认 42 |
| --target-points <n> | 图片采样的目标规模 / 基础预算;scatter 默认约 11000,bead 默认约 6400 |
| --total-points <n> | --target-points 的别名 |
| --width <n> / --height <n> | 输出画布尺寸;高度默认按输入宽高比推导 |
| --background <color> | 覆盖画布背景,如 #F4EFE6 或 transparent |
| --points <file> | 生成并保存 Visual Point IR |
| --out <file.svg> | 写出 SVG;未指定任何输出文件时 SVG 写入 stdout |
| --png <file.png> | 同时写出 PNG |
| --html <file.html> | 写出交互式透镜页面 |
| --inspect <file> | 输出点数、region、layer 与 occupancy 统计 |
| --validate <file> | 对 Point JSON 做运行时结构检查 |
| --viewer <file.html> | 写出面向开发调试的 Point IR Viewer |
--target-points/--total-points是视觉预算,不是严格的最终点数承诺。规则网格会按画布比例取整。
TypeScript API
当前仓库采用 TypeScript source-first 方式提供 API,适合在仓库内通过 tsx 或由上层 bundler 集成。
import { writeFileSync } from "node:fs";
import { runPipeline } from "./src/index.ts";
const { points, svg } = runPipeline({
image: "examples/portrait-reference.png",
generate: {
layout: "scatter",
seed: 42,
targetPoints: 8000,
},
render: {
preset: "dot",
width: 1200,
},
});
writeFileSync("out/portrait-points.json", JSON.stringify(points, null, 2));
writeFileSync("out/portrait.svg", svg ?? "");公开入口还包括:
- Sampling:
generatePoints、createSamplingEngine、createPointSampler - Representation:
createPoint、createVisualScene、toVisualScene - Rendering:
createSvgRenderer、registerRenderer - Tooling:
renderSvg、exportPng、exportHtml、inspectPointDocument
设计原则
- Data before pixels — 先得到可保存的视觉数据,再决定最终如何绘制。
- Determinism over accidental beauty — 随机性必须受 seed 控制,结果必须可以重放。
- Pixels decide color — 有参考图时,真实像素决定颜色,采样只决定点落在哪里。
- Renderers never generate points — Renderer 只读 Visual IR,不拥有采样逻辑,也不回读图片。
- LLM describes; code constructs — 模型可以描述结构,但几何、点位、取色与渲染始终由代码完成。
项目结构
src/
├── analyzer/ 输入归一化与使用规则
├── core/ Pipeline 与公共类型契约
├── representation/ Visual Point IR、校验与旧格式迁移
├── sampler/ Scatter 与 bead grid 采样
├── renderer/ SVG renderer、registry 与输出工具
└── utils/ 图片解码、像素采样、边缘与色板工具
schema/ Point / Visual IR Schema
presets/ Dot、bead、default 外观
examples/ 图片、IR 与交互输出
tests/ 确定性、采样、IR、渲染器、CLI 与工具测试质量与能力边界
项目测试覆盖以下关键契约:
- 相同 seed 的 Point IR 与 SVG 可复现
- PNG/JPEG 像素采样与格式识别
- 归一化坐标和跨尺寸重渲染
- Visual IR 校验、旧 Point JSON 迁移与 JSON round-trip
- SVG renderer 与自定义 renderer 注册
- SVG → PNG、Interactive HTML 与 Debug Viewer 输出
当前边界:
- 当前稳定输入聚焦 PNG/JPEG,运行时聚焦 Node.js 离线资产生成。
- 项目不做前景分割或透明背景自动抠图;边缘用于细节增强,而不是分割掩膜。
- 当前稳定渲染路径是 SVG;Canvas / Particle 保留为扩展方向。
开发
# 运行完整测试
npm test欢迎通过 Issues 提交问题、功能建议与真实案例,也欢迎围绕 renderer、sampling strategy、Schema 和示例画廊发起 Pull Request。
路线图
- 可注入的 Analyzer / Sampler / Renderer pipeline
- 更严格的全局 point budget 与 JSON Schema runtime validation
- Canvas / Particle renderer
- 标准化 npm package、类型声明与 CLI binary
- 大规模点场景 benchmark 与性能优化
