Skip to content

Instantly share code, notes, and snippets.

@wingcd
Created September 21, 2023 06:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wingcd/aec3b915a2a53d94f398cd3727366755 to your computer and use it in GitHub Desktop.
Save wingcd/aec3b915a2a53d94f398cd3727366755 to your computer and use it in GitHub Desktop.
change fairygui project's design resolution,will scale all images and components
const path = require('path');
const fs = require('fs');
const { createCanvas, loadImage } = require("canvas");
const sizeOf = require('image-size');
const libxmljs = require("libxmljs2");
const scaleRate = 0.85;
const rootDir = path.join(__dirname, "../../mergeFGUI/FGUIProject");
const assetDir = path.join(rootDir, "assets");
const packages = [
];
let allPackages = fs.readdirSync(assetDir);
allPackages.forEach(t => {
let pkg = t;
packages.push(pkg);
});
const ignorePaths = [
];
const attributesFixMap = {
// loader: {
// "Beginner/ModelEnergyItem/bg": {
// "fill":"scale",
// },
// "Shop/ModelDiscounts/bg": {
// "fill":"scale",
// }
// }
}
Object.keys(attributesFixMap).forEach(t => {
let item = attributesFixMap[t];
Object.keys(attributesFixMap[t]).forEach(k => {
let sk = k.toLocaleLowerCase();
let fixMap = item[k];
item[sk] = fixMap;
delete item[k];
});
});
function getImageScaleSize(width, height, scale, is9Grid) {
let minSize = 1;
if(is9Grid) {
minSize = 3;
}
const options = [width, height].map((item) => Math.round(item * scale));
if(options.width <= minSize || options.height <= minSize) {
if(is9Grid) {
if(options.width <= minSize && options.height <= minSize) {
return;
}else if(options.width <= minSize) {
options.width = width;
}else if(options.height <= minSize) {
options.height = height;
}
}else{
return;
}
}
return options;
}
/**
* 缩放图片
* @param srcImg 待缩放的图片路径
* @param scale 缩放比例
*/
async function resizeCurrentImg(srcImg, scale, is9Grid) {
try{
console.log(`缩放图片:${srcImg}, ${scale}`);
const image = await loadImage(fs.readFileSync(srcImg));
const { width, height } = image;
const options = getImageScaleSize(width, height, scale, is9Grid);
if(!options) {
return;
}
const canvas = createCanvas(...options);
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, ...options);
saveTextFile(srcImg, canvas.toBuffer(), true);
}catch(e) {
console.error(`缩放图片失败:${srcImg}`, e);
}
}
function getPackageDir (packageName) {
return path.join(rootDir, "assets", packageName);
}
function getKey(pkg,comp,id) {
return `${pkg}/${comp}/${id}`.toLocaleLowerCase();
}
function getResources () {
let resourceDB = {};
allPackages.forEach(packageName => {
let packageDir = getPackageDir(packageName);
let packagePath = path.join(packageDir, "package.xml");
// 解析package
let packageData = fs.readFileSync(packagePath, "utf-8");
let packageXml = libxmljs.parseXmlString(packageData);
let allRes = packageXml.get("/packageDescription/resources").childNodes();
allRes.forEach(t => {
if(!t.attr) return;
let id = t.attr("id").value();
let fpath = t.attr("path").value();
let fname = t.attr("name").value();
let file = path.join(packageDir, fpath, fname);
if(resourceDB[id]) {
console.error(`资源id重复:${id}`, resourceDB[id], file);
return;
}
resourceDB[id] = {
file,
res: t,
};
});
});
return resourceDB;
}
function modifyPackage(resItemNode) {
let changed = false;
let name = resItemNode.name();
if(name == "image") {
let scale9grid = resItemNode.attr("scale9grid")?.value();
if(scale9grid) {
let scale9gridArr = scale9grid.split(",");
let x = parseInt(scale9gridArr[0]);
let y = parseInt(scale9gridArr[1]);
let w = parseInt(scale9gridArr[2]);
let h = parseInt(scale9gridArr[3]);
let newScale9grid = `${Math.round(x * scaleRate)},${Math.round(y * scaleRate)},${Math.round(w * scaleRate)},${Math.round(h * scaleRate)}`;
resItemNode.attr("scale9grid", newScale9grid);
changed = true;
}
}
return changed;
}
var needScaleImages = {};
var needScaleComps = {};
function collectInfos (resourceDB, packageName) {
let packageDir = getPackageDir(packageName);
let imgs = {};
let comps = {};
let packagePath = path.join(packageDir, "package.xml");
// 解析package
let packageData = fs.readFileSync(packagePath, "utf-8");
let packageXml = libxmljs.parseXmlString(packageData);
let allRes = packageXml.get('/packageDescription/resources').childNodes();
allRes.forEach(t => {
if(!t.attr) return;
let name = t.name();
let id = t.attr("id").value();
let fpath = t.attr("path").value();
let fname = t.attr("name").value();
if(name == "component") {
let file = path.join(packageDir, fpath, fname);;
comps[id] = file;
}else if(name == "image") {
if(ignorePaths.some(p => fpath.toLowerCase().indexOf(p) >= 0)) {
return;
}
imgs[id] = resourceDB[id].file;
}
});
// 设置组件大小为固定值
Object.keys(comps).forEach(t => {
needScaleComps[t] = comps[t];
});
// 缩放图片
Object.keys(imgs).forEach(t => {
needScaleImages[t] = imgs[t];
});
}
function scaleVec4(strVal, scaleRate) {
let vecArr = strVal.split(',');
let x = parseInt(vecArr[0]);
let y = parseInt(vecArr[1]);
let newX = Math.round(x * scaleRate);
let newY = Math.round(y * scaleRate);
let newVecArr = [];
for(let i=0;i<vecArr.length;i++) {
if(i == 0) {
newVecArr.push(newX.toString());
}else if(i==1){
newVecArr.push(newY.toString());
}else{
// 后两位忽略,一般为按比例时存储的值, 或者存储的缩放
newVecArr.push(vecArr[i]);
}
}
return newVecArr.join(",");
}
function modifyDisplays(parent, child, scaleRate) {
let changed = false;
let size = child.attr("size")
// 缩放本身大小
if(size) {
let sizeArr = size.value().split(',');
let w = parseInt(sizeArr[0]);
let h = parseInt(sizeArr[1]);
if(w > 1 && h > 1) {
let newSize = [Math.round(w * scaleRate), parseInt(h * scaleRate)];
child.attr("size", `${newSize[0]},${newSize[1]}`);
changed = true;
}
}
// 修改位置
let xy = child.attr("xy");
if(xy) {
let xyArr = xy.value().split(',');
let x = parseInt(xyArr[0]);
let y = parseInt(xyArr[1]);
let newX = Math.round(x * scaleRate);
let newY = Math.round(y * scaleRate);
child.attr("xy", `${newX},${newY}`);
changed = true;
}
// 修改字体大小
let fontSize = child.attr("fontSize");
if(fontSize) {
let fontSizeVal = parseInt(fontSize.value());
let newFontSize = Math.round(fontSizeVal * scaleRate);
child.attr("fontSize", `${newFontSize}`);
}
// 修改控制器属性
let controller = child.childNodes();
if(controller) {
controller.forEach(t => {
if(!t.attr) return;
let name = t.name();
if(name == "gearXY" || name == "gearSize") {
let values = t.attr("values")?.value();
if(values) {
let pagePosArr = values.split('|');
let newValues = [];
pagePosArr.forEach(pagePos => {
newValues.push(scaleVec4(pagePos, scaleRate));
});
t.attr("values", newValues.join("|"));
changed = true;
}
}
});
}
return changed;
}
function modifyTransition(parent, child, scaleRate) {
let changed = false;
let startValue = child.attr("startValue")?.value();
let endValue = child.attr("endValue")?.value();
if(startValue) {
child.attr("startValue", scaleVec4(startValue, scaleRate));
changed = true;
}
if(endValue) {
child.attr("endValue", scaleVec4(endValue, scaleRate));
changed = true;
}
return changed;
}
function scaleComponent(compFile, scaleRate) {
if(!fs.existsSync(compFile)) {
console.error(`组件文件不存在:${compFile}`);
return;
}
let changed = false;
let compData = fs.readFileSync(compFile, "utf-8");
let compXml = libxmljs.parseXmlString(compData);
let component = compXml.get('/component');
changed = modifyDisplays(null, component, scaleRate) || changed;
// 缩放子节点
let compParent = compXml.get('/component');
let displayList = compXml.get('/component/displayList')?.childNodes();
if(displayList) {
displayList.forEach(t => {
if(!t.attr) return;
changed = modifyDisplays(compParent, t, scaleRate) || changed;
});
}
let transitions = compXml.get('/component/transition')?.childNodes();
if(transitions) {
transitions.forEach(t => {
if(!t.attr) return;
changed = modifyTransition(compParent, t, scaleRate) || changed;
});
}
if(changed) {
console.log(`修改组件:${compFile}`);
let xmlData = compXml.toString();
saveTextFile(compFile, xmlData);
}
}
function scaleAllComponent (components) {
Object.keys(components).forEach(t => {
let compFile = components[t];
scaleComponent(compFile, scaleRate);
});
}
function scaleAllImage(images) {
Object.keys(images).forEach(t => {
let imgFile = images[t];
let item = allResources[t].res;
let is9Grid = item.attr("scale")?.value() == "9grid";
resizeCurrentImg(imgFile, scaleRate, is9Grid);
});
}
function scaleAllPackage() {
packages.forEach(t => {
let packageDir = getPackageDir(t);
let packagePath = path.join(packageDir, "package.xml");
let packageStr = fs.readFileSync(packagePath, "utf-8");
let packageXml = libxmljs.parseXmlString(packageStr);
let allRes = packageXml.get('/packageDescription/resources').childNodes();
if(allRes) {
let changed = false;
allRes.forEach(res => {
changed = modifyPackage(res) || changed;
});
if(changed) {
saveTextFile(packagePath, packageXml.toString());
}
}
});
}
function saveTextFile(filename, content, isBuffer) {
fs.writeFileSync(filename, content);
// if(!isBuffer) {
// console.log(filename, content);
// }
}
var allResources = getResources();
function resizeAll () {
packages.forEach(t => {
collectInfos(allResources, t);
});
scaleAllPackage();
scaleAllComponent(needScaleComps);
scaleAllImage(needScaleImages);
}
resizeAll();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment