spritegen-png-cli
Version:
从图标文件夹中生成Maplibre/Mapbox精灵图
94 lines (80 loc) • 3.25 kB
JavaScript
import fs from 'fs';
import path from 'path';
import fg from 'fast-glob';
import chokidar from 'chokidar';
import Jimp from 'jimp';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const Spritesmith = require('spritesmith');
export async function buildSprites(options) {
const {
input, out, name, padding, ext, ratios, scale2x, watch
} = options;
const exts = ext.split(',').map(e => e.trim().toLowerCase());
const ratioList = ratios.split(',').map(r => Number(r.trim()));
const build = async () => {
const files = await fg(exts.map(e => `${input}/**/*.${e}`));
if (!files.length) {
console.warn('[spritegen] No images found.');
return;
}
// build 1x
const result1x = await runSpritesmith(files, Number(padding));
await writeOutput(result1x, out, name, 1);
// build other ratios
for (const ratio of ratioList) {
if (ratio === 1) continue;
if (scale2x && ratio === 2) {
const upscaled = await upscale(result1x, 2);
await writeOutput(upscaled, out, name, 2);
} else {
const result = await runSpritesmith(files, Number(padding));
await writeOutput(result, out, name, ratio);
}
}
};
await build();
if (watch) {
console.log(`[spritegen] Watching folder: ${input}`);
chokidar.watch(input, { ignoreInitial: true }).on('all', build);
}
}
function runSpritesmith(files, padding) {
return new Promise((resolve, reject) => {
Spritesmith.run({ src: files, padding }, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
}
async function upscale(result, scale) {
const img = await Jimp.read(result.image);
img.scale(scale);
const image = await img.getBufferAsync(Jimp.MIME_PNG);
const coords = {};
for (const [file, info] of Object.entries(result.coordinates)) {
coords[file] = {
x: Math.round(info.x * scale),
y: Math.round(info.y * scale),
width: Math.round(info.width * scale),
height: Math.round(info.height * scale)
};
}
return { image, coordinates: coords, properties: result.properties };
}
async function writeOutput(result, outDir, baseName, ratio) {
fs.mkdirSync(outDir, { recursive: true });
const pngPath = path.join(outDir, `${baseName}${ratio === 1 ? '' : `@${ratio}x`}.png`);
const jsonPath = path.join(outDir, `${baseName}${ratio === 1 ? '' : `@${ratio}x`}.json`);
await fs.promises.writeFile(pngPath, result.image);
await fs.promises.writeFile(jsonPath, JSON.stringify(toMetadata(result.coordinates, ratio), null, 2));
console.log(`[spritegen] Generated: ${pngPath}, ${jsonPath}`);
}
function toMetadata(coordinates, pixelRatio) {
const meta = {};
for (const [file, info] of Object.entries(coordinates)) {
const name = path.basename(file, path.extname(file));
meta[name] = { ...info, pixelRatio };
}
return meta;
}