优化第一阶段
This commit is contained in:
115
lib/plugins/ktx2/compressor.js
Normal file
115
lib/plugins/ktx2/compressor.js
Normal file
@ -0,0 +1,115 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { spawn } from "child_process";
|
||||
import color from "picocolors";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const toktx = path.join(__dirname, "..", "..", "..", "bin", "texture_tool.exe");
|
||||
|
||||
// 检查 toktx 是否存在
|
||||
export function checkToktx() {
|
||||
if (!fs.existsSync(toktx)) {
|
||||
console.error("❌ 找不到 texture_tool.exe");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 扫描图片文件
|
||||
export function scanImages(exts) {
|
||||
console.log("🔍 扫描目标文件中...");
|
||||
const cwd = process.cwd();
|
||||
const images = fs.readdirSync(cwd).filter(f =>
|
||||
exts.some(ext => f.toLowerCase().endsWith("." + ext))
|
||||
);
|
||||
return { images, cwd };
|
||||
}
|
||||
|
||||
// 构建压缩参数
|
||||
export function buildArgs(input, output, config) {
|
||||
const args = ["--t2"];
|
||||
|
||||
if (config.encoding === "uastc") {
|
||||
args.push("--encode", "uastc");
|
||||
const zcmpLevel = { none: "0", standard: "10", high: "18", extreme: "22" };
|
||||
args.push("--zcmp", zcmpLevel[config.quality] || "10");
|
||||
} else if (config.encoding === "etc1s") {
|
||||
args.push("--encode", "etc1s");
|
||||
} else if (config.encoding === "astc") {
|
||||
args.push("--encode", "astc");
|
||||
const blkSize = { none: "8x8", standard: "6x6", high: "5x5", extreme: "4x4" };
|
||||
args.push("--astc_blk_d", blkSize[config.quality] || "6x6");
|
||||
}
|
||||
|
||||
if (config.mipmap === "auto") {
|
||||
args.push("--genmipmap");
|
||||
}
|
||||
|
||||
args.push(output, input);
|
||||
return args;
|
||||
}
|
||||
|
||||
// 压缩单个文件
|
||||
export function compressFile(img, config, cwd, progress) {
|
||||
const baseName = img.replace(/\.[^.]+$/, "");
|
||||
const out = baseName + ".ktx2";
|
||||
|
||||
// 点动画
|
||||
let dots = 0;
|
||||
const dotAnim = setInterval(() => {
|
||||
const dotStr = ".".repeat(dots);
|
||||
process.stdout.write(`\r${progress} ${img} 正在转换中${dotStr} `);
|
||||
dots = dots >= 3 ? 0 : dots + 1;
|
||||
}, 300);
|
||||
|
||||
process.stdout.write(`${progress} ${img} 正在转换中.`);
|
||||
|
||||
const args = buildArgs(img, out, config);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn(toktx, args, { cwd });
|
||||
|
||||
let stderr = "";
|
||||
proc.stderr?.on("data", data => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
|
||||
proc.on("close", code => {
|
||||
clearInterval(dotAnim);
|
||||
if (code === 0) {
|
||||
console.log(`\r${progress} ${color.green("✓")} ${out} `);
|
||||
resolve({ success: true });
|
||||
} else {
|
||||
console.log(`\r${progress} ${color.red("✗")} ${img} 失败 `);
|
||||
if (stderr) {
|
||||
console.log(color.dim(` 错误: ${stderr.trim()}`));
|
||||
}
|
||||
resolve({ success: false, error: stderr });
|
||||
}
|
||||
});
|
||||
|
||||
proc.on("error", err => {
|
||||
clearInterval(dotAnim);
|
||||
console.log(`\r${progress} ${color.red("✗")} ${img} 失败 `);
|
||||
console.log(color.dim(` 错误: ${err.message}`));
|
||||
resolve({ success: false, error: err.message });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 批量压缩
|
||||
export async function compressAll(images, config, cwd) {
|
||||
const total = images.length;
|
||||
let finished = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const img of images) {
|
||||
finished++;
|
||||
const progress = `(${finished}/${total})`;
|
||||
const result = await compressFile(img, config, cwd, progress);
|
||||
if (!result.success) failed++;
|
||||
}
|
||||
|
||||
return { total, failed };
|
||||
}
|
||||
Reference in New Issue
Block a user