UNPKG

plistunpacker

Version:

这个包目前可以将texturepacker打包导出的plist文件分割成对应的小图片

299 lines (273 loc) 9.19 kB
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;