使用Vim修复Sprite Sheet Editor 0.5.6版生成的错误XML文件
Sprite Sheet Editor 0.5.6有一个很重大的Bug,在保存metadata的时候,我将frame的ow/oh属性保存成了与w/h属性相同的值。
根据Sprite Sheet Editor修剪每帧中的空白区域的原理说明可以知道,对于剪切过空白的帧来说,ow和oh是还原原始帧大小的关键。如果这两个值出错,会导致无法取得动画的正确尺寸。
好在这个是可以回溯的。可以通过比较某个Label包含的所有帧的尺寸,通过ox/oy和w/h计算出每帧的实际尺寸,最大的那一个,就是该Label中的所有帧的统一ow/oh属性值。
使用这个方法,得到的实际值,甚至比原来通过Sprite Sheet Editor进行手工设定的值更小,也就是更加节省内存。
选择什么工具处理?AS3有强悍的E4X,JAVA和BASH也不错。但我正好想学习下Vim脚本,就用它了!
处理思路:
- metadata中的
<labels>
标签中保存所有Label的帧索引; - 取得每个Label的帧索引,获取每帧的行号,保存;
- 针对每个Label进行处理,通过Label中每帧的ox/oy/w/h计算出ow/oh;
- 记录每个Label中最大的ow/oh;
- 用最大的ow/oh替换该Label中所有帧的ow/oh;
- 循环处理所有Label。
1" 转换Sprite Sheet Editor 0.5.6版生成的错误XML文件
2" zrong (zrongzrong@gmail.com) 2011-09-02
3
4" 获取当前目录下的所有xml文件
5let xmls = split(glob("*.xml"), "\")
6" 执行批量修复工作
7for b:xml in xmls
8 echom 'progress '.b:xml
9 call RepareWH(b:xml)
10endfor
11
12" 修复file参数提供的xml文件
13function! RepareWH(file)
14 exec 'sp '.a:file
15 normal gg
16 let labelStart = search('')+1
17 " 找不到Label,处理所有帧
18 if labelStart <= 1
19 echom 'label not found'
20 let framesLine = GetFrames()
21 call WriteFrames(range(len(framesLine)), framesLine)
22 update
23 close
24 return
25 endif
26 let labelEnd = search('<\/labels>')-1
27 let labels = []
28 " 将所有的label名称与对应的帧索引写入一个List
29 " List中的每一项是一个字典,name是label名称,index帧索引的数组(字符串形式保存)
30 for i in range(labelStart, labelEnd)
31 let labelMatch = matchlist(getline(i), '<\(\w\+\)>\([0-9,]\+\)')
32 call add(labels, {'name':labelMatch[1], 'index':split(labelMatch[2], ',')})
33 endfor
34 normal gg
35 let framesLine = GetFrames()
36 echom 'find '.len(framesLine).' frames'
37 " 修复所有的label
38 for label in labels
39 echo 'progress label '.label.name
40 call WriteFrames(label.index, framesLine)
41 endfor
42 update
43 close
44endfunction
45
46" 将所有的frame块转换成字典,并存入list
47function! GetFrames()
48 let framesLine = []
49 while search('','',line('$'))
50 let frameStart = line(".")+1
51 let frameEnd = search('<\/frame>')-1
52 call add(framesLine, ParseFrame(frameStart, frameEnd))
53 endwhile
54 return framesLine
55endfunction
56
57" 将一帧的信息转换成字典,并返回
58function! ParseFrame(start, end)
59 let aFrame = {}
60 let reg = '<\(\w\+\)>\([-0-9]\+\)'
61 for lineIndex in range(a:start, a:end)
62 let matchFrame = matchlist(getline(lineIndex), reg)
63 let aFrame[matchFrame[1]] = str2nr(matchFrame[2])
64 " 写入ow和oh的行号方便后面替换
65 if matchFrame[1] =~ 'ow'
66 let aFrame.owl = lineIndex
67 endif
68 if matchFrame[1] =~ 'oh'
69 let aFrame.ohl = lineIndex
70 endif
71 endfor
72 return aFrame
73endfunction
74
75" 计算真实尺寸的最大值,将最大值写入这一组帧
76function! WriteFrames(frameIndexs, framesLine)
77 let owMax = 0
78 let ohMax = 0
79 for index in a:frameIndexs
80 "echo '== progress frame '.index
81 let l:frame = a:framesLine[str2nr(index)]
82 " 如果修剪尺寸小于原始尺寸,则说明该帧没有问题
83 if l:frame.w < l:frame.ow && l:frame.h < l:frame.oh
84 "echom 'this frame '.index.' is not problem'
85 continue
86 endif
87 " 真实的帧大小,是用修剪大小减去偏移值
88 let trueW = l:frame.w - l:frame.ox
89 let trueH = l:frame.h - l:frame.oy
90 " 更新真实帧大小的最大值
91 if trueW > owMax
92 let owMax = trueW
93 endif
94 if trueH > ohMax
95 let ohMax = trueH
96 endif
97 endfor
98 if owMax > 0 && ohMax > 0
99 " 写入帧的真实大小
100 for index in a:frameIndexs
101 let l:frame = a:framesLine[str2nr(index)]
102 let ows = substitute(getline(l:frame.owl), '\d\+', owMax, '')
103 let ohs = substitute(getline(l:frame.ohl), '\d\+', ohMax, '')
104 echo '== write frame '.index.' line:'.l:frame.owl.','.l:frame.ohl.' w:'.owMax.' h:'.ohMax
105 call setline(l:frame.owl, ows)
106 call setline(l:frame.ohl, ohs)
107 endfor
108 endif
109endfunction
- 文章ID:1435
- 原文作者:zrong
- 原文链接:https://blog.zengrong.net/post/fix-sse-056-xml-bug-with-vim/
- 版权声明:本作品采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可,非商业转载请注明出处(原文作者,原文链接),商业转载请联系作者获得授权。