1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | # This file is part of PARPG. |
---|
4 | |
---|
5 | # PARPG is free software: you can redistribute it and/or modify |
---|
6 | # it under the terms of the GNU General Public License as published by |
---|
7 | # the Free Software Foundation, either version 3 of the License, or |
---|
8 | # (at your option) any later version. |
---|
9 | |
---|
10 | # PARPG is distributed in the hope that it will be useful, |
---|
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | # GNU General Public License for more details. |
---|
14 | |
---|
15 | # You should have received a copy of the GNU General Public License |
---|
16 | # along with PARPG. If not, see <http://www.gnu.org/licenses/> |
---|
17 | |
---|
18 | import sys, pygame |
---|
19 | |
---|
20 | # place defines here |
---|
21 | |
---|
22 | TILE_WIDTH = 72 |
---|
23 | TILE_HEIGHT = 36 |
---|
24 | # is this is true, output a file of the pics together in the current folder |
---|
25 | STITCH = False |
---|
26 | |
---|
27 | # this is very much a simple routine, but we still have a simple class |
---|
28 | |
---|
29 | class TileImage: |
---|
30 | def __init__(self, picture, name, yoff): |
---|
31 | self.image = picture |
---|
32 | self.filename = name |
---|
33 | self.y_offset = yoff |
---|
34 | |
---|
35 | def writeXML(name, yoff): |
---|
36 | """Write the XML file as well |
---|
37 | Always the same small file so we do it automatically""" |
---|
38 | # we need to strip off the entire path up to the last |
---|
39 | # TODO: this code will not work on windows |
---|
40 | # strip off the png part and replace with the XML |
---|
41 | filename = name.split('/')[-1] |
---|
42 | if(filename == name): |
---|
43 | filename = name.split('\\')[-1] |
---|
44 | x_file = open(name[:-4]+".xml","wt") |
---|
45 | x_file.write('''<?fife type="object"?>\n''') |
---|
46 | x_file.write('''<object id="''') |
---|
47 | x_file.write(filename[:-4]) |
---|
48 | x_file.write('''" namespace="PARPG" blocking="1" static="1">\n''') |
---|
49 | x_file.write(''' <image source="''') |
---|
50 | x_file.write(filename) |
---|
51 | x_file.write('''" direction="0"''') |
---|
52 | x_file.write(''' y_offset="''') |
---|
53 | x_file.write(yoff) |
---|
54 | x_file.write('''" />\n''') |
---|
55 | # the \n\n is ESSENTIAL otherwise the XML parser in FIFE craps out! |
---|
56 | x_file.write('''</object>\n\n''') |
---|
57 | x_file.close |
---|
58 | |
---|
59 | def stitchImages(files, width, height): |
---|
60 | """Put the images together and output them to stitched.png""" |
---|
61 | new_image=pygame.Surface((width, height), pygame.SRCALPHA, 32) |
---|
62 | xpos = 0 |
---|
63 | for i in files: |
---|
64 | new_image.blit(i.image, (xpos, 0)) |
---|
65 | xpos += i.image.get_width() |
---|
66 | pygame.image.save(new_image,"stitched.png") |
---|
67 | |
---|
68 | def saveFiles(files): |
---|
69 | """Given a list of TileImages, output them as seperate files |
---|
70 | Returns True if it worked""" |
---|
71 | # files is a list of TileImages |
---|
72 | complete = [] |
---|
73 | width = 0 |
---|
74 | height = 0 |
---|
75 | for i in files: |
---|
76 | width += i.image.get_width() |
---|
77 | if(i.image.get_height() > height): |
---|
78 | height = i.image.get_height() |
---|
79 | try: |
---|
80 | pygame.image.save(i.image, i.filename) |
---|
81 | # output the XML file as well |
---|
82 | writeXML(i.filename, str(i.y_offset)) |
---|
83 | except: |
---|
84 | print "Error: Failed to save",i.filename |
---|
85 | # if we saved some anyway, then tell the user |
---|
86 | if(complete != []): |
---|
87 | print " Managed to save", |
---|
88 | for name in complete: |
---|
89 | print name, |
---|
90 | print "\n" |
---|
91 | return False |
---|
92 | complete.append(i.filename) |
---|
93 | # seems like all was ok |
---|
94 | if(STITCH == True): |
---|
95 | stitchImages(files, width, height) |
---|
96 | return True |
---|
97 | |
---|
98 | def splitImage(image, filename, data): |
---|
99 | """Quite complex this, as there are many differing layouts on the |
---|
100 | hexes that we could be dealing with. We blit from left to right |
---|
101 | data holds the hex position changes in [x,y] format. |
---|
102 | by one and the y value staying the same (on the grid map)""" |
---|
103 | # the starting point for the grab is always the middle of the image |
---|
104 | height = (image.get_height() / 2) + (TILE_HEIGHT / 2) |
---|
105 | xpos = 0 |
---|
106 | file_counter = 0 |
---|
107 | tiles = [] |
---|
108 | height_adjust = 0 |
---|
109 | yoff_next = -((height - TILE_HEIGHT) / 2) |
---|
110 | for t in data: |
---|
111 | yoff = yoff_next |
---|
112 | if(t == 'm'): |
---|
113 | # switchback, so this tile must fill the whole width |
---|
114 | width += TILE_WIDTH / 2 |
---|
115 | height_adjust = TILE_HEIGHT / 2 |
---|
116 | yoff_next += (TILE_HEIGHT / 4) + (TILE_HEIGHT / 2) |
---|
117 | xoff = 0 |
---|
118 | elif(t == 'r'): |
---|
119 | # moving forward on the y axis |
---|
120 | width = TILE_WIDTH / 2 |
---|
121 | height_adjust = - (TILE_HEIGHT / 2) |
---|
122 | yoff_next += TILE_HEIGHT / 4 |
---|
123 | xoff = TILE_WIDTH / 2 |
---|
124 | elif(t == 'l'): |
---|
125 | # moving forward on the x axis |
---|
126 | width = TILE_WIDTH / 2 |
---|
127 | height_adjust = TILE_HEIGHT / 2 |
---|
128 | yoff_next -= TILE_HEIGHT / 4 |
---|
129 | xoff = 0 |
---|
130 | else: |
---|
131 | # TODO: Handle integer moves (i.e. > 1 tile up down) |
---|
132 | print "Error: Can't handle integer tile moves yet" |
---|
133 | sys.exit(False) |
---|
134 | # if the image is 256, then adjust |
---|
135 | # bug in the FIFE OpenGL code |
---|
136 | if(height == 256): |
---|
137 | height += 1 |
---|
138 | # build the new surface |
---|
139 | new_surface = pygame.Surface((TILE_WIDTH, height), pygame.SRCALPHA, 32) |
---|
140 | # now blit a strip of the image across |
---|
141 | new_surface.blit(image, (0+xoff, 0), pygame.Rect(xpos, 0, width, height)) |
---|
142 | # store the image for later |
---|
143 | tiles.append(TileImage(new_surface, |
---|
144 | filename + chr(ord('a')+file_counter) + ".png",yoff)) |
---|
145 | file_counter += 1 |
---|
146 | # amend variables |
---|
147 | xpos += width |
---|
148 | height += height_adjust |
---|
149 | return tiles |
---|
150 | |
---|
151 | def convertFiles(filename, txt_data): |
---|
152 | """Take a file, slice into seperate images and then save these new images |
---|
153 | as filename0, filename1 ... filenameN |
---|
154 | Returns True if everything worked |
---|
155 | The second string gives the offsets from left to right. The first tile |
---|
156 | on the LHS MUST be in the centre of the image""" |
---|
157 | # first we need to ensure that the data sent is correct. split it up first |
---|
158 | data=[] |
---|
159 | for i in txt_data: |
---|
160 | data.append(i) |
---|
161 | if(len(data) < 2): |
---|
162 | print "Error: Invalid tile data layout" |
---|
163 | return False |
---|
164 | # validate each data statement |
---|
165 | for i in data: |
---|
166 | if((i != 'l')and(i != 'r')and(i != 'm')and(i.isdigit()==False)): |
---|
167 | # some issue |
---|
168 | print "Error: Can't decode tile string structure" |
---|
169 | return False |
---|
170 | # then load the file |
---|
171 | try: |
---|
172 | image = pygame.image.load(filename) |
---|
173 | except(pygame.error): |
---|
174 | print "Error: Couldn't load",filename |
---|
175 | return False |
---|
176 | # split into seperate files |
---|
177 | # the [:-4] is used to split off the .png from the filename |
---|
178 | images = splitImage(image, filename[:-4], data) |
---|
179 | # save it and we are done |
---|
180 | if(images == []): |
---|
181 | # something funny happened |
---|
182 | print "Error: Couldn't splice given image file" |
---|
183 | return False |
---|
184 | return(saveFiles(images)) |
---|
185 | |
---|
186 | if __name__=="__main__": |
---|
187 | # check we have some options |
---|
188 | if(len(sys.argv) < 3): |
---|
189 | sys.stderr.write("Error: Not enough data given\n") |
---|
190 | sys.exit(False) |
---|
191 | # ok, so init pygame and do it |
---|
192 | pygame.init() |
---|
193 | sys.exit(convertFiles(sys.argv[1], sys.argv[2])) |
---|
194 | |
---|