-
-
Save wingcd/aec3b915a2a53d94f398cd3727366755 to your computer and use it in GitHub Desktop.
change fairygui project's design resolution,will scale all images and components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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