YiffyBeds/scripts/images.ts

118 lines
3.5 KiB
TypeScript
Raw Permalink Normal View History

2024-07-27 23:46:56 +00:00
import type { PathLike } from "fs";
import { access } from "fs/promises";
import { dirname, resolve } from "path";
import sharp, { type OverlayOptions } from "sharp";
import { parseArgs } from "util";
import { formatImage, makeKZ } from "./common";
import { readFile } from "fs/promises";
import { writeFile } from "fs/promises";
import { rm } from "fs/promises";
import { mkdir } from "fs/promises";
import { stat } from "fs/promises";
import { readdir } from "fs/promises";
const { values: args } = parseArgs({
args: Bun.argv,
options: {
images: {
type: "string",
short: "i",
default: "images/images.json"
},
imagedir: {
type: "string",
short: "d",
default: "images"
},
outdir: {
type: "string",
short: "o",
default: "data"
},
basefile: {
type: "string",
short: "b",
default: "base.png"
},
throw: {
type: "boolean",
short: "t",
default: false
}
},
strict: true,
allowPositionals: true
});
const dirExists = async(path: PathLike) => access(path).then(() => true, () => false);
const imagesPath = resolve(args.images ?? "images.json");
const imageDir = resolve(args.imagedir ?? dirname(imagesPath));
const baseFile = resolve(args.basefile ?? "base.png");
const outDir = resolve(args.outdir ?? "data");
const throwOnMissing = !!args.throw;
if (!await dirExists(imageDir)) {
console.error("Image directory %s does not exist.", imageDir);
process.exit(1);
}
const ap = (p: string) => resolve(p, "assets/minecraft/textures/entity/bed");
// const ap = (p: string) => resolve(p, "../img");
await rm(`${outDir}/assets`, { recursive: true, force: true });
await mkdir(ap(outDir), { recursive: true });
export interface Image {
animation?: { frametime?: number; };
frames?: { start: number; end?: number; } | Array<number>;
name: string;
sizeMultiplier?: number;
rotate?: number;
flip?: "horizontal" | "vertical";
}
export interface Detail {
pos: [number, number];
size: [number, number];
cut: [number, number];
rotate?: number;
flip?: "horizontal" | "vertical";
}
export interface Details {
top: Detail;
middle: Detail;
bottom: Detail;
}
export interface Config {
defaultSize: [width: number, height: number];
details: Details;
images: Array<Image>;
}
const config = await Bun.file(imagesPath).json() as Config;
for (const image of config.images) {
let img: string | Array<string>;
if (await stat(`${imageDir}/${image.name}`).then(s => s.isDirectory(), () => false)) {
img = await readdir(`${imageDir}/${image.name}`).then(files => files.map(f => `${imageDir}/${image.name}/${f}`).sort());
} else {
const [file] = await Array.fromAsync(new Bun.Glob(`${image.name}.*`).scan({ onlyFiles: true, cwd: imageDir }));
if (!file) {
console.error("Image %s does not exist.", image.name);
if (throwOnMissing) {
process.exit(1);
}
continue;
}
img = `${imageDir}/${file}`
}
console.log("Processing %s", image.name);
const { isImage, result } = await formatImage(image.name, baseFile, config, img);
await result.toFile(`${ap(outDir)}/${image.name}.png`);
if (!isImage) {
await writeFile(`${ap(outDir)}/${image.name}.png.mcmeta`, JSON.stringify({ animation: image.animation ?? {} }));
}
}