初学python 解析atlas拆解spine图片

python作为脚本语言,还是十分的不错的,拥有强大的模块库供开发者使用。开发过程中,解释器会将python代码解析为字节码或字节码文件.pyc,有时候会将部分字节码进行优化为二进制指令,虽然无法跟c,c++在性能上相比较,除非你对性能的要求比较高,python已然足够,即当你需要性能或者发现性能的时候再去考虑性能,或许也是为时不晚的。python同时也是oop面向对象的,这对于熟悉c++的开发人员来说,python其实在代码编写和设计上是十分熟悉的,能够快速的掌握。

大多数情况下,我们用python都只是用其写一个脚本,帮助我们完成一些重复的自动化的工作,比如cocos中的setup.py环境变量设置,ndk编译和资源拷贝都可以让python去处理,甚至是生成c++代码,辅助我们去编写游戏。在游戏中,大多重复的劳动是耗费在ui界面上,但是大多ui界面基本都大同小异,比如大多数界面都需要一串按钮,点击关闭就关闭界面,点击领取就给服务端发送相关的解析,各个功能之间的差别极小,往往只需要添加一点点条件或者状态判断即可。这时候脚本就显得闪闪发光了!(GP泛型编程也能解决代码复用的问题,甚至性能和效率上更优于cwithclass的做法,这里不做考虑)

接下来,我简单介绍下python中常用的功能、模块(2.7.7):

#coding=utf-8整个文件以utf-8编码保存

os,sys,time,platform,Queue,shutil(PIL,Tkinter),光作为脚本以上模块已经基本够用,如果做python服务器或者web,threading,mutiprocess或许用的更多(但是我想用python做web的应该不算多吧- -)

print,type,isinstance,reload,raw_input,input,fopen方法也是比较重要

list,tuple,dict,int,float,str等作为基本的数据类型,使用度更不用说(注意:切片功能十分重要,enumerate可生成key,value成对的list,整型、字符串、tuple是不可变,作为参数传入的时候传的其实是原始值的拷贝,list可变)

还有更多强大的功能可以去看python教程(*arg,**kw,metaclass,reduce,map,iter,@property):

接下来是解析atlas:

atlas: spine骨骼动画导出的类似于plist功能的json格式文件,用来表示打包图中碎块的位置,大小等信息,网上有很多拆plist,缺好像没见拆atlas的数据,所以这里用python实现了一下:

kbtools.py (简单的功能模块,不依赖于类对象的放在tools模块中)

#coding=utf-8
import os,sys,platform,time
from os.path import *
from tkMessageBox import *
__auther__='cjsjy123'

global Res,Total_Times,Logs_Times,Total_File_Nums,M_RES_LIST,ALL_FILE_LIST
#总共消耗的时间
Total_Times =[float(0),]
#单个函数消耗的时间字符串
Logs_Times=[]
#总文件数
Total_File_Nums =[0,]
#for search
Res =[0,]

M_RES_LIST =[]
ALL_FILE_LIST=[]

def getinfo():
	getTFnums()
	getTtimes()
	getTFtimes()

def getTFnums():
	result_print('@F total file nums : %d \n' % Total_File_Nums[0])
def getTtimes():
	result_print('@T total times is : %f seconds \n' % Total_Times[0])
def getTFtimes():
	result_print('@f total fun times info : %s \n' % Logs_Times)

def log_time(fun):
	def take_time(*arg,**kw):
		start =time.time()
		val = fun(*arg,**kw)
		end =time.time()
		result_print('Function: %s ,it takes %f seconds'% (fun.__name__,end-start))
		Logs_Times.append('Function: %s ,it takes %f seconds'% (fun.__name__,end-start))
		Total_Times[0] += end-start
		return val
	return take_time

def checkVer():
	if int(platform.python_version().split('.')[0])>=3:
		errinfo = 'Now you are using %s,plz refer to 2.7(2.x)!' % platform.python_version()
		showerror('ERROR',errinfo)
		return False
	else:
		result_print('It\'s Ok. The version is %s' % (platform.python_version()))
		return True

def file_switch(file,fullpath):
	global Res,Total_File_Nums
	Res[0] =1
	Total_File_Nums[0] +=1
	print 'ENTER!!!!! %s   == %s' % (file,fullpath)
	# print 'test %s' % file
	if isdir(fullpath):
		print 'enter 111'
		ALL_FILE_LIST.append(fullpath)
		result_print ('found it\'s dir: %s' % fullpath)
	elif isfile(fullpath):
		print 'enter 222'
		ALL_FILE_LIST.append(fullpath)
		result_print ('found it\'s %s file: %s' % (splitext(fullpath)[1],fullpath))
	else:
		print 'enter 333'
		ALL_FILE_LIST.append(fullpath)
		result_print ('found it\'s Unknown File :%s' % fullpath)

def check_utf8(str):
	if isinstance(str,unicode):
		print 'str :%s  is unicode'% str
	else:
		print 'str :%s is utf8' % str

# @log_time
def FileSearch(str ='',search_path =''):
	def visit(arg,dirname,files):
		for file in files:
			full_path = join(dirname,file)
			print 'full=== %s'% full_path
			if arg.upper() in file.upper():
				file_switch(file,full_path)
	name =str
	global Total_File_Nums
	Total_File_Nums =[0,]
	if str =='':
		name = raw_input('input something in order to search in the curent dir and subs:\n')
		name = name.encode('utf-8')

	if search_path == '':
		print '-1'
		walk(os.getcwd(),visit,name)
	else:
		print '-2 %s' % name
		walk(search_path,visit,name)
	#check result
	if Res[0]==0:
		result_print('Not Found!')
	else:
		info ='Found %s Files'% Total_File_Nums[0]
		showinfo('FIND_INFO',info)

def result_print(str):
	global M_RES_LIST
	M_RES_LIST.append(str+'\n')

if __name__ == '__main__':
	print checkVer()

#coding=utf-8
import os,sys,time,platform
from os.path import *
from tkCommonDialog import Dialog
from Tkinter import *
from tkFileDialog import *
from tkMessageBox import *
from ScrolledText import *
from kbtools import *
try:
	import Image
except ImportError:
	showerror('Error','Not Found Image module')

__auther__='cjsjy123'

#数据格式 元表
SPINE_STRUCT =('png_path','format','filter','size_wid','size_hei','repeat')


class AntiAtlas:
	'''
	@ATLAS_STRUCT,pnglist
	girl.png
	size: 1017,510
	format: RGBA8888
	filter: Linear,Linear
	repeat: none
	attment
  		rotate: false
  		xy: 541, 159
  		size: 37, 23
  		orig: 39, 25
  		offset: 1, 1
  		index: -1
	'''
	def __init__(self,file_path='.'):
		self.ATLAS_STRUCT ={}
		self.pnglist =[]
		self.file_path =file_path;
		self.ResourcePath =''
		self.flag=False

	@log_time
	def start_analyze(self,m_view=None):
		if checkVer():
			print '\n----start analyzing------\n'
			print 'The current platform is %s' % sys.platform
			#windows
			if sys.platform =='win32':
				if self.file_path.endswith('.atlas')== False:
					showerror('Error','Not Atlas File ! plz check it !')
				elif exists(self.file_path) ==False:
					showerror('Error','Not Dound Atlas File ! plz check it !')
				else:
					with open(self.file_path,'r') as f:
						# print f.read()
						# self.oldatlas =f.read()
						# linenum=0;
						for lines in f.readlines():
							# linenum +=1
							# print ' len %d num : %d  %s' %(len(lines),linenum,lines)
							#去除空格
							self.analyze(''.join(lines.split()))
						# self.ATLAS_STRUCT['pnglist'] = self.pnglist
					self.img =Image.open(self.ResourcePath)
					self.split_png()
					if m_view != None:
						m_view.result_text.insert(END,M_RES_LIST)
			#mac
			elif sys.plaform == 'darwin':
				pass
	'''
	warning:  attment cant include ':'
	rotate
	x y
	width height
	orig_x orig_y
	offset_x offset_y
	index
	'''
	def singlePng(self,str):
		if ':' in str:
			if str.startswith('rotate'):
				if str.split(':')[-1] =='false':
					self.pnglist[-1]['rotate'] = False
				else:
					self.pnglist[-1]['rotate'] = True
			elif str.startswith('xy'):
				self.pnglist[-1]['x']          = int(str.split(':')[-1].split(',')[0])
				self.pnglist[-1]['y']          = int(str.split(':')[-1].split(',')[-1])
			elif str.startswith('size'):
				self.pnglist[-1]['width']      = int(str.split(':')[-1].split(',')[0])
				self.pnglist[-1]['height']     = int(str.split(':')[-1].split(',')[-1])
			elif str.startswith('orig'):
				self.pnglist[-1]['orig_x']     = int(str.split(':')[-1].split(',')[0])
				self.pnglist[-1]['orig_y']     = int(str.split(':')[-1].split(',')[-1])
			elif str.startswith('offset'):
				self.pnglist[-1]['offset_x']   = int(str.split(':')[-1].split(',')[0])
				self.pnglist[-1]['offset_y']   = int(str.split(':')[-1].split(',')[-1])
			elif str.startswith('index'):
				self.pnglist[-1]['index']      = int(str.split(':')[-1])
		else:
			newDic={}
			newDic['attmentname'] =str
			self.pnglist.append(newDic)

	def analyze(self,str):
		# print '==== %s --- %d  ~~ %s **** %s'% (str,len(str),self.flag,str.find('png'))
		if str != '':
			if self.flag ==False:
				if str.find('.png') != -1:
					self.ATLAS_STRUCT[SPINE_STRUCT[0]]   = str
					self.ResourcePath                    = str
				elif str.startswith('format'):
					self.ATLAS_STRUCT[SPINE_STRUCT[1]]   = str.split(':')[-1]
				elif str.startswith('filter'):
					self.ATLAS_STRUCT[SPINE_STRUCT[2]]   = str.split(':')[-1]
				elif str.startswith('size'):
					self.ATLAS_STRUCT[SPINE_STRUCT[3]]   = int(str.split(':')[-1].split(',')[0])
					self.ATLAS_STRUCT[SPINE_STRUCT[4]]   = int(str.split(':')[-1].split(',')[-1])
				elif str.startswith('repeat'):
					self.ATLAS_STRUCT[SPINE_STRUCT[5]]   = str.split(':')[-1]
					self.flag= True
			else:
				self.singlePng(str)

	def split_png(self):
		if self.ResourcePath =='':
			showerror('Error','png path error in atlas ! plz check atlas or *.png')
		else:
			print self.img.format,self.img.size,self.img.mode
			# print self.ResourcePath
			for each in self.pnglist:
				print 'each --%s' % each
				org_x  = int(each['x'])
				org_y  = int(each['y'])
				wid    = int(each['width'])
				height = int(each['height'])
				if each['rotate'] ==True:
					region = (org_x,org_y,org_x+height,org_y+wid)
				elif each['rotate'] ==False:
					region = (org_x,org_y,org_x+wid,org_y+height)
				print '============ %d %d %d %d' %(org_x,org_y,wid,height)
				#裁切图片
				cropImg= self.img.crop(region)
				export_dir_name = self.ResourcePath.split('.')[0] +'_export'
				export_full_path =os.path.join(os.getcwd(),export_dir_name)
				print '----- %s  %s' %( exists(export_full_path),isdir(export_full_path))
				if exists(export_full_path) and isdir(export_full_path):
					print 'it has created !'
				else:
					os.mkdir(export_full_path)
				#保存裁切后的图片
				if each['rotate'] ==True:
					cropImg =cropImg.rotate(270)
					print type(cropImg)
				elif  each['rotate'] ==False:
					cropImg =cropImg.rotate(0)

				print 'path ----- %s' % (os.path.join(export_full_path,each['attmentname']+'.png'))
				cropImg.save(os.path.join(export_full_path,each['attmentname']+'.png'))

#view
class View(Frame):
	def __init__(self,parent,master =None):
		Frame.__init__(self,parent,master)
		self.parent = parent
		#680,384

		self.pack(fill=BOTH,expand =1)
		self.btlist  = []
		self.lbllist = []
		self.editlist= []
		self.searchpath =os.getcwd()
		self.atlat_searchpath =os.getcwd()
		self.createWindow()

	def createWindow(self):
		scnWidth = self.parent.winfo_screenwidth()
		scnHeight = self.parent.winfo_screenheight()
		info ='%sx%s+%s+%s' %(600,500,scnWidth/2 -250,scnHeight/2-250)
		self.parent.geometry(info)

		self.label_1 =Label(self,text ='文件搜索功能:')
		self.label_1.grid(row =0,column=0,sticky=E+W+S+N)

		self.a_label_1 =Label(self,text ='atlas拆分:')
		self.a_label_1.grid(row =2,column=0,sticky=E+W+S+N)
		# self.label_1.pack(fill=BOTH,side =LEFT)
		self.search_bt =Button(self,text ='开始搜索',command=self.cbk_start_search)
		self.search_bt.grid(row=0,column=4,sticky=E+W+S+N)

		self.a_search_bt =Button(self,text ='开始解析',command=self.cbk_start_analize)
		self.a_search_bt.grid(row=2,column=4,sticky=E+W+S+N)

		self.search_bt =Button(self,text ='清空',command=self.clear)
		self.search_bt.grid(row=0,column=10,sticky=E+W+S+N,ipadx=30)

		self.check_val =[0,]
		self.check_bt=Checkbutton(self,text ='只搜索atlas',command=self.cbk_check)
		self.check_bt.grid(row=3, column=8)

		self.s_defalut_name =StringVar()
		self.s_defalut_name.set('请输入关键字 ')
		self.s_Input = Entry(self,textvariable =self.s_defalut_name)
		self.s_Input.grid(row=0,column=2,columnspan=2,padx =10,sticky=E+W+S+N,ipadx=50)

		self.s_choice_b =Button(self,text ='...',command=self.cbk_search)
		self.s_choice_b.grid(row=0, column=8,sticky=E+W+S+N,padx=10,ipadx =10)

		self.a_choice_b =Button(self,text ='...',command=self.cbk_atlas_search)
		self.a_choice_b.grid(row=2,column =8,sticky=E+W,padx=10,ipadx=10)

		self.a_defalut_name =StringVar()
		self.a_defalut_name.set('请输入atlas和png所在的文件夹 ')
		self.a_Input = Entry(self,textvariable =self.a_defalut_name)
		self.a_Input.grid(row=2,column=2,columnspan=2,padx =10,sticky=E+W+S+N,ipadx=50)

		self.result_text = ScrolledText(bg='white', height=35)
		self.result_text.focus_set()
		self.result_text.pack(fill=BOTH)

	def clear(self):
		print 'size %s' % self.result_text.size

	def cbk_check(self):
		if self.check_val[0] == 1:
			self.check_val[0] = 0
		elif self.check_val[0] == 0:
			self.check_val[0] =1

	def cbk_search(self):
		self.searchpath = askdirectory()

	def cbk_atlas_search(self):
		self.atlat_searchpath = askdirectory()

	def cbk_start_search(self):
		global ALL_FILE_LIST
		st=self.s_defalut_name.get().encode('utf-8')
		print '==============================  %s' % st
		FileSearch(st,self.searchpath)
		print '%s --- %s' % (st,self.searchpath)

		if self.check_val[0] ==1:
			temp_list=[]
			print '3'
			for each in ALL_FILE_LIST:
				if each.find('.atlas') !=-1:
					temp_list.append(each)
			ALL_FILE_LIST=temp_list
		for val in ALL_FILE_LIST:
			info='Found '+splitext(val)[-1]+'  file  '+val+'\n'
			self.result_text.insert(END,info)

	def cbk_start_analize(self):
		for each in ALL_FILE_LIST:
			print each
			anti =AntiAtlas(each)
			anti.start_analyze()

if __name__ == '__main__':
	root = Tk()
	App = View(root)
	App.master.title('AntiAtlas 工具')
	App.mainloop()

	# FileSearch('.atlas')
	# getinfo()
	# anti =AntiAtlas('spineboy.atlas')
	# anti.start_analyze()
	# print anti.ATLAS_STRUCT
	# showinfo('INFO','it finished')
	# raw_input()

log_time装饰器和time模块用来测试函数时间,os.path去调整路径,encode去转换编码,tkinter显示ui界面,golbal 表示全局变量,PIL拆解图片(PIL不是内置模块,需要额外下载安装)

最后搞了个冻结二进制(将PVM和代码全部打包成一个exe文件),用pyinstaller。简单工具,bug还是有的~不过影响不大。注意要先安装PIL哦,先放出EXE:Antiatlas

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页