plistunpacker
Version:
这个包目前可以将texturepacker打包导出的plist文件分割成对应的小图片
299 lines (273 loc) • 9.19 kB
JavaScript
const fs = require('fs');
const path = require('path');
const xmlStringToJson = require('xml2js').parseString;
// const images = require("images");
const sharp = require("sharp");
// const im = require('imagemagick');
class UnPacker {
constructor(command) {
this.start = new Date();
this.totalPlist = 0;
this.nowPlist = 0;
this.nowErrorPlist = 0;
this.totalImg = 0;
this.nowImg = 0;
command.infofile = path.resolve(command.infofile)
var filePath = command.infofile;
this.command = command;
var self = this;
fs.exists(filePath, (exists) => {
if(!exists) {
throw new Error('文件不存在')
}
fs.stat(filePath, (err, stats) => {
if(err) {
throw new Error('无法获取文件信息 ')
}
if(stats.isFile()) {
self.totalPlist = 1;
command.type = 'file';
command.baseroot = path.join(command.infofile, '..');
command.output = path.join(command.baseroot, command.output);
self.CheckAndCreateDir(command.output, ()=>{
self.CheckAndHandle(filePath);
});
} else if(stats.isDirectory()) {
command.type = 'directory';
command.baseroot = command.infofile;
command.output = path.join(command.baseroot, '..', command.output);
self.CheckAndCreateDir(command.output, ()=>{
self.GetFileList(filePath);
});
} else {
throw new Error('不支持的文件类型');
}
})
});
}
UnPackerPlist (plistPath) {
var self = this;
var command = this.command;
if(command.detail) {
console.log(plistPath);
}
fs.readFile(plistPath, 'utf-8', (err, xmlString) => {
if (err) {throw new Error('读取Plist文件出错:'+plistPath);}
xmlStringToJson(xmlString, (xmlError, json) => {
if(xmlError) {throw new Error('解析Xml格式文件为Json出现错误');}
if (json.plist.$.version !== '1.0') {throw new Error('不支持的Plist文件版本!!!');}
var plistName = path.basename(plistPath, path.extname(plistPath));
var storeBase = command.output;
if(command.split) {
storeBase = path.join(command.output, plistName);
}
self.CheckAndCreateDir(storeBase, () => {
var imagePath = path.join(command.baseroot, self.GetImageName(json));
var img = sharp(imagePath);
var imgDict = self.GetImageDict(json);
var imgList = self.GetImageList(imgDict);
self.totalImg += imgList.length;
fs.exists(imagePath, (imgExist) => {
if(imgExist) {
var nowItemImg = 0;
imgList.forEach(item => {
if(command.detail) {
console.log('正在保存文件:'+item.name+'...');
}
var sX = item.frameStartX;
var sY = item.frameStartY;
var w = item.frameWidth;
var h = item.frameHeight;
var rotation = 0;
if (item.rotated) {
w+=h;
h=w-h;
w=w-h;
rotation = 270;
}
sharp(imagePath).extract({left:sX, top: sY, width:w, height:h}).rotate(rotation).toFile(path.join(storeBase, item.name), error => {
if (error) {
console.log(path.join(storeBase, item.name));
console.error(plistPath+'保存文件:'+item.name+'出错');
console.error('程序运行结束。共解析图片:'+self.nowImg+'张,共'+self.totalImg+'张图片,解析'+self.nowPlist+'个plist文件,共'+self.totalPlist+'个plist文件');
console.log('程序解析时长:'+(new Date().getTime() - self.start.getTime())/1000+'秒');
throw error;
} else {
console.log('保存文件:'+path.join(storeBase, item.name)+' 成功');
nowItemImg++;
self.nowImg++;
if (nowItemImg == imgList.length) {
self.nowPlist++;
}
if(self.nowPlist + self.nowErrorPlist == self.totalPlist) {
console.log('程序运行结束。共解析图片:'+self.nowImg+'张,共'+self.totalImg+'张图片,解析'+self.nowPlist+'个plist文件,共'+self.totalPlist+'个plist文件');
console.log('程序解析时长:'+(new Date().getTime() - self.start.getTime())/1000+'秒');
}
}
});
});
} else {
self.nowErrorPlist++;
}
})
});
})
})
}
CheckAndHandle(filePath) {
var eName = path.extname(filePath);
if(eName && eName!='') {
if (eName.toLocaleLowerCase() === '.plist') {
this.totalPlist++;
this.UnPackerPlist(filePath);
}
}
}
CheckAndCreateDir(p, callback) {
var command = this.command;
fs.exists(p, (exists) => {
if(!exists) {
fs.mkdir(p, (mkerr) => {
if (mkerr) {throw new Error('创建输出文件夹出错');}
callback();
});
} else {
fs.stat(p, (sErr, stats) => {
if(sErr) {throw new Error("无法获取文件信息:"+p);}
if(stats.isFile()) {throw Error('输出路径为文件,无法创建输出文件夹');}
callback();
})
}
})
}
/*
GetOutputPath() {
return path.format({
dir:command.baseroot,
base:command.output
});
}
*/
GetFileList(dirPath) {
var self = this;
fs.readdir(dirPath, (err, files) => {
files.forEach(file => {
var itemFilePath = path.join(dirPath, file);
fs.stat(itemFilePath, (ferr, stats) => {
if(ferr) {
throw new Error('读取文件出错:'+itemFilePath);
}
if (stats.isFile()) {
self.CheckAndHandle(itemFilePath);
}
})
})
})
}
GetImageName (json) {
var metadataIndex = this.IndexOf(json.plist.dict[0].key, 'metadata');
if (metadataIndex == -1) { console.error('no metadata found, cant not load image file with image name');return;}
var metadata = json.plist.dict[0].dict[metadataIndex];
var formatIndex = metadata.key.indexOf('format');
var realTextureFileNameIndex = this.IndexOf(metadata.key, 'realTextureFileName');
if (formatIndex<realTextureFileNameIndex) {realTextureFileNameIndex--;}
if (realTextureFileNameIndex <= -1) { console.error('no metadata found, cant not load image file with image name');return;}
var realTextureFileName = metadata.string[realTextureFileNameIndex];
return realTextureFileName;
}
GetImageDict(json) {
var framesIndex = this.IndexOf(json.plist.dict[0].key, 'frames');
if (framesIndex == -1) { console.error('can not find frames');return;}
return json.plist.dict[0].dict[framesIndex];
}
GetImageList(dict) {
var imgList = [];
for(var i = 0; i < dict.key.length; i++) {
var img = {};
img.name = dict.key[i];
var imgInfo = dict.dict[i];
var keys = imgInfo.key;
var stringIndex = 0;
var boolIndex = 0;
for(var j=0;j<keys.length;j++) {
var key = keys[j];
if (key === 'rotated') {
if (imgInfo.true) {
img.rotated = true;
} else {
img.rotated = false;
}
} else {
var data = imgInfo.string[stringIndex++];
if (key === 'frame') {
data = data.split(/,|{|}/);
img.frameStartX = parseInt(data[2]);
img.frameStartY = parseInt(data[3]);
img.frameWidth = parseInt(data[6]);
img.frameHeight = parseInt(data[7]);
} else if(key === 'offset') {
data = data.split(/,|{|}/);
img.offsetX = parseInt(data[1]);
img.offsetY = parseInt(data[2]);
} else if(key === 'sourceSize') {
data = data.split(/,|{|}/);
img.sourceSizeWidth = parseInt(data[1]);
img.sourceSizeHeight = parseInt(data[2]);
} else if(key === 'sourceColorRect') {
data = data.split(/,|{|}/);
img.sourceColorRectX = parseInt(data[2]);
img.sourceColorRectY = parseInt(data[3]);
img.sourceColorRectWidth = parseInt(data[6]);
img.sourceColorRectHeight = parseInt(data[7]);
} else {
img[key] = data;
}
}
}
imgList.push(img);
}
return imgList;
}
IndexOf(arr, value, fromindex) {
var len=arr.length;
//如果arr不是数组或者第一个参数为空或者undefined,则返回false
if(toString.call(arr) !== '[object Array]' || value === '' || value === undefined || toString.call(value) === '[object Function]'){
return false;
}
//默认第一个参数为0
if(fromindex === undefined){
fromindex = 0;
}
//第二个参数不是数字返回false
if(toString.call(fromindex) !== '[object Number]'){
return false;
}
//判断第二个参数是否为负数
if(fromindex<0){
fromindex = Math.abs(fromindex);
//超过搜索范围
if(len < fromindex){
return -1;
}else{
//负数则从后面开始向后搜索
fromindex = len - fromindex;
}
}
//开始查找
for(var i=0+fromindex;i<len;i++){
if(value === arr[i]){
return i;
}else{
//判断数据类型相等
if(toString.call(arr[i]) === toString.call(value)){
//判断数据值相等
if(JSON.stringify(arr[i]) === JSON.stringify(value)){
return i;
}
}
}
}
return -1;
}
}
module.exports = UnPacker;