119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import packer, { packAsync, type TexturePackerOptions } from "free-tex-packer-core"
|
|
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length < 2) {
|
|
console.log('Usage: sillypacker <inputFolder> <outputFolder>');
|
|
process.exit(1);
|
|
}
|
|
|
|
const inputFolder = args[0];
|
|
const outputFolder = args[1];
|
|
|
|
console.log(`Input Folder: ${inputFolder}`);
|
|
console.log(`Output Folder: ${outputFolder}`);
|
|
|
|
type FileImage = {
|
|
path: string,
|
|
contents: Buffer<ArrayBufferLike>,
|
|
}
|
|
|
|
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff'];
|
|
const isImageFile = (fileName: string) => imageExtensions.some(ext => fileName.toLowerCase().endsWith(ext));
|
|
|
|
const getImageFiles = (dirPath: string): FileImage[] => {
|
|
const files:FileImage[] = [];
|
|
const items = fs.readdirSync(dirPath);
|
|
|
|
items.forEach((item) => {
|
|
const fullPath = path.join(dirPath, item);
|
|
const stats = fs.statSync(fullPath);
|
|
const basename = path.basename(fullPath);
|
|
|
|
if (stats.isDirectory())
|
|
files.push(...getImageFiles(fullPath));
|
|
else if (stats.isFile() && isImageFile(item))
|
|
files.push({path: basename, contents: fs.readFileSync(fullPath)});
|
|
|
|
});
|
|
|
|
return files;
|
|
};
|
|
|
|
const images = getImageFiles(inputFolder);
|
|
|
|
const sorter = (a, b) => {
|
|
let prefixA = a.match(/[a-zA-Z]+/)[0];
|
|
let numA = parseInt(a.match(/\d+/)[0]);
|
|
|
|
let prefixB = b.match(/[a-zA-Z]+/)[0];
|
|
let numB = parseInt(b.match(/\d+/)[0]);
|
|
|
|
if (prefixA === prefixB) {
|
|
return numA - numB;
|
|
} else {
|
|
return prefixA.localeCompare(prefixB);
|
|
}
|
|
}
|
|
|
|
let options:TexturePackerOptions = {
|
|
textureName: path.basename(inputFolder),
|
|
removeFileExtension: true,
|
|
prependFolderName: false,
|
|
width: 128,
|
|
height: 128,
|
|
powerOfTwo: true,
|
|
padding: 2,
|
|
extrude: 0,
|
|
allowRotation: true,
|
|
allowTrim: true,
|
|
detectIdentical: true,
|
|
trimMode: "trim",
|
|
packer: "OptimalPacker",
|
|
exporter: "JsonArray"
|
|
};
|
|
|
|
packer(images, options, (files, error) => {
|
|
if (error) {
|
|
console.error('Packaging failed', error);
|
|
} else {
|
|
const meta = files.filter(i => i.name.endsWith(".json"))
|
|
.map(i => JSON.parse(i.buffer.toString("utf-8")))
|
|
.map(i => {
|
|
const images = i.frames.map(frame => {
|
|
const name = frame.filename;
|
|
const texcord_x = frame.frame.x
|
|
const texcord_y = frame.frame.y
|
|
const texcord_w = frame.frame.w
|
|
const texcord_h = frame.frame.h
|
|
const offset_x = frame.spriteSourceSize.x
|
|
const offset_y = frame.spriteSourceSize.y
|
|
const width = frame.sourceSize.w
|
|
const height = frame.sourceSize.h
|
|
const rotated = (frame.rotated) ? 1 : 0;
|
|
|
|
return {name, texcord_x, texcord_y, texcord_w, texcord_h, offset_x, offset_y, width, height, rotated}
|
|
}).toSorted();
|
|
|
|
const name = i.meta.image;
|
|
return {name, images}
|
|
})
|
|
|
|
// fs.writeFileSync(
|
|
// path.join("dist", options.textureName + ".json"),
|
|
// JSON.stringify(meta, null, 2),
|
|
// "utf-8");
|
|
|
|
const out = [`sillyatl ${meta.length}`, meta.map(tex => [`${path.basename(tex.name, path.extname(tex.name))} ${tex.images.length}`, ...tex.images.map(img => {
|
|
return `${img.name} ${img.texcord_x} ${img.texcord_y} ${img.texcord_w} ${img.texcord_h} ${img.offset_x} ${img.offset_y} ${img.width} ${img.height} ${img.rotated}`
|
|
}).toSorted((a, b) => sorter(a,b))].join("\n"))].flat().join("\n");
|
|
|
|
fs.writeFileSync(path.join(outputFolder, options.textureName + ".txt"), out, "utf-8");
|
|
|
|
|
|
const texture = files.filter(i => i.name.endsWith(".png"))
|
|
.map(i => fs.writeFileSync(path.join(outputFolder, i.name), i.buffer));
|
|
}
|
|
}); |