cut / BeadQR /miniprogram /utils /palette.js
Ethscriptions's picture
上传 BeadQR 微信小程序项目源码
9de7b70 verified
Raw History Blame Contribute Delete
2.66 kB
// MARD 色库预设 + 预处理(Typed Array 结构,供匹配引擎高速读取)
const { MARD_PALETTE, MARD_SMART_ORDER } = require('./palette-data')
const { hexToRgb, rgbToOklabInto, luma } = require('./color')
// 颜色匹配模式:darkMax/lightMin 为二维码深/浅模块允许的亮度范围
const MATCH_MODES = [
{ id: 'rich', label: '色彩优先', hint: '更像原图', darkMax: 0.4, lightMin: 0.74 },
{ id: 'balanced', label: '均衡', hint: '推荐', darkMax: 0.36, lightMin: 0.78 },
{ id: 'strict', label: '扫码优先', hint: '最稳', darkMax: 0.3, lightMin: 0.84 },
]
const byId = new Map(MARD_PALETTE.map((c) => [c.id, c]))
const pick = (ids) => ids.map((id) => byId.get(id)).filter(Boolean)
const STANDARD_221 = MARD_PALETTE.filter((c) => /^[A-HM]\d+$/.test(c.id))
const PRESETS = [
{ id: '221', label: '标准 221 色', short: '221 色', detail: 'MARD 标准色,最常见', list: () => STANDARD_221 },
{ id: '291', label: '完整 291 色', short: '291 色', detail: '含扩展色,颜色最全', list: () => MARD_PALETTE },
...[144, 96, 72, 48, 24].map((n) => ({
id: String(n),
label: `精选 ${n} 色`,
short: `${n} 色`,
detail: n <= 48 ? '入门套装,买豆更省' : '常用色,兼顾效果与成本',
list: () => pick(MARD_SMART_ORDER.slice(0, n)),
})),
]
const cache = {}
function preparePalette(presetId) {
if (cache[presetId]) return cache[presetId]
const preset = PRESETS.find((p) => p.id === presetId) || PRESETS[0]
const list = preset.list()
const n = list.length
const rgb = new Uint8Array(n * 3)
const lab = new Float32Array(n * 3)
const lum = new Float32Array(n)
list.forEach((c, i) => {
const [r, g, b] = hexToRgb(c.hex)
rgb[i * 3] = r; rgb[i * 3 + 1] = g; rgb[i * 3 + 2] = b
rgbToOklabInto(r, g, b, lab, i * 3)
lum[i] = luma(r, g, b)
})
// 色与色之间的距离矩阵(291² ≈ 8.5 万项,一次性计算)
const pair = new Float32Array(n * n)
for (let i = 0; i < n; i += 1) {
for (let j = i + 1; j < n; j += 1) {
const dl = lab[i * 3] - lab[j * 3]
const da = lab[i * 3 + 1] - lab[j * 3 + 1]
const db = lab[i * 3 + 2] - lab[j * 3 + 2]
const d = Math.sqrt(dl * dl + da * da + db * db)
pair[i * n + j] = d
pair[j * n + i] = d
}
}
const prepared = {
id: preset.id,
label: preset.label,
short: preset.short,
n,
ids: list.map((c) => c.id),
hexes: list.map((c) => c.hex),
rgb,
lab,
lum,
pair,
subsets: {},
luts: {},
}
cache[presetId] = prepared
return prepared
}
module.exports = { MATCH_MODES, PRESETS, preparePalette }