82 lines
2.3 KiB
JavaScript
82 lines
2.3 KiB
JavaScript
import sharp from 'sharp';
|
|
import { resolve, basename, extname, join, dirname } from 'path';
|
|
import { existsSync, mkdirSync, readdirSync, statSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const PROJECT_ROOT = resolve(fileURLToPath(import.meta.url), '../../..');
|
|
const DEFAULT_INPUT = resolve(PROJECT_ROOT, 'assets/items');
|
|
const DEFAULT_OUTPUT = resolve(PROJECT_ROOT, 'assets/icons');
|
|
const GRID = 4;
|
|
const SUPPORTED_EXTENSIONS = /\.(jpe?g|png|webp|tiff?)$/i;
|
|
|
|
async function splitSpriteSheet(filePath, outputDir) {
|
|
const name = basename(filePath, extname(filePath));
|
|
|
|
const { width, height } = await sharp(filePath).metadata();
|
|
const cellWidth = Math.floor(width / GRID);
|
|
const cellHeight = Math.floor(height / GRID);
|
|
|
|
const tasks = [];
|
|
|
|
for (let row = 0; row < GRID; row++) {
|
|
for (let col = 0; col < GRID; col++) {
|
|
const left = col * cellWidth;
|
|
const top = row * cellHeight;
|
|
const outputPath = join(outputDir, `${name}-${row}-${col}.png`);
|
|
|
|
tasks.push(
|
|
sharp(filePath)
|
|
.extract({ left, top, width: cellWidth, height: cellHeight })
|
|
.png()
|
|
.toFile(outputPath)
|
|
.then(() => outputPath)
|
|
);
|
|
}
|
|
}
|
|
|
|
return Promise.all(tasks);
|
|
}
|
|
|
|
function collectFiles(input) {
|
|
if (statSync(input).isFile()) {
|
|
return [input];
|
|
}
|
|
return readdirSync(input)
|
|
.filter(f => SUPPORTED_EXTENSIONS.test(f))
|
|
.map(f => join(input, f));
|
|
}
|
|
|
|
async function main() {
|
|
const input = resolve(process.argv[2] || DEFAULT_INPUT);
|
|
const outputDir = resolve(process.argv[3] || DEFAULT_OUTPUT);
|
|
|
|
if (!existsSync(input)) {
|
|
console.error(`Not found: ${input}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
mkdirSync(outputDir, { recursive: true });
|
|
|
|
const files = collectFiles(input);
|
|
|
|
if (files.length === 0) {
|
|
console.error(`No image files found in: ${input}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Processing ${files.length} sprite sheet(s)...`);
|
|
|
|
const allResults = await Promise.all(
|
|
files.map(async (filePath) => {
|
|
const results = await splitSpriteSheet(filePath, outputDir);
|
|
console.log(` ${basename(filePath)} -> ${results.length} images`);
|
|
return results;
|
|
})
|
|
);
|
|
|
|
const totalImages = allResults.reduce((sum, r) => sum + r.length, 0);
|
|
console.log(`Done. ${totalImages} images saved to ${outputDir}`);
|
|
}
|
|
|
|
main();
|