Mercurial > repos > ghero
annotate tiles2img.py @ 6:3148b6389042
Set dynamic colors to 8 in tiles2img
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 03 Sep 2013 09:37:10 -0700 |
parents | 97ec271a513f |
children |
rev | line source |
---|---|
3 | 1 #!/usr/bin/env python |
2 from PIL import Image | |
3 | |
4 def gchannel(Val): | |
5 return (Val >> 4) & 0xE | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
6 |
3 | 7 threshold = 127 |
8 | |
9 def get_color_info(pixels, rng, threshold, exclude={}): | |
10 gencolors = {} | |
11 A = 255 | |
12 for idx in rng: | |
13 color = pixels[idx] | |
14 if len(color) == 4: | |
15 (R, G, B, A) = color | |
16 else: | |
17 (R, G, B) = color | |
18 if A > threshold: | |
19 gcolor = (gchannel(R), gchannel(G), gchannel(B)) | |
20 if not gcolor in exclude: | |
21 if gcolor in gencolors: | |
22 gencolors[gcolor] += 1 | |
23 else: | |
24 gencolors[gcolor] = 1 | |
25 glist = [(gencolors[color], color) for color in gencolors] | |
26 glist.sort() | |
27 glist.reverse() | |
28 return glist | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
29 |
3 | 30 def totiles(im, palette): |
31 pass | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
32 |
3 | 33 def make_palette(im, trans_thresh, max_global, max_line): |
34 pixels = im.getdata() | |
35 (width, height) = im.size | |
36 colors = get_color_info(pixels, xrange(0, height * width), trans_thresh) | |
37 glob_pal = {} | |
38 for idx in xrange(0, min(max_global, len(colors))): | |
39 (count, color) = colors[idx] | |
40 glob_pal[color] = idx | |
41 line_pals = [] | |
42 if max_global < len(colors): | |
43 for line in xrange(0, height): | |
44 linestart = line * width | |
45 linecolors = get_color_info(pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal) | |
46 line_pal = {} | |
47 for idx in xrange(0, min(max_line, len(linecolors))): | |
48 (count, color) = linecolors[idx] | |
49 line_pal[color] = idx | |
50 line_pals.append(line_pal) | |
51 return (glob_pal, line_pals) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
52 |
3 | 53 def color_dist(a, b): |
54 (ra, ga, ba) = a | |
55 (rb, gb, bb) = b | |
56 return abs(ra-rb)**2 + abs(ga-gb)**2 + abs(ba-bb)**2 | |
57 | |
58 def trans_image(im, trans_thresh, pal): | |
59 (global_pal, line_pals) = pal | |
60 pixels = im.getdata() | |
61 (width, height) = im.size | |
62 gpixels = [] | |
63 A = 255 | |
64 x = 0 | |
65 y = 0 | |
66 for pixel in pixels: | |
67 if x == width: | |
68 x = 0 | |
69 y += 1 | |
70 if width % 8: | |
71 for i in xrange(0, 8-(width%8)): | |
72 gpixels.append(0) | |
73 if len(pixel) == 4: | |
74 (R, G, B, A) = pixel | |
75 else: | |
76 (R, G, B) = pixel | |
77 if A > trans_thresh: | |
78 gpixel = (gchannel(R), gchannel(G), gchannel(B)) | |
79 if gpixel in global_pal: | |
80 gpixels.append(global_pal[gpixel]) | |
81 elif gpixel in line_pals[y]: | |
82 gpixels.append(line_pals[y][gpixel] + len(global_pal)) | |
83 else: | |
84 bestdist = color_dist((0,0,0), (15, 15, 15)) | |
85 bestpal = 0 | |
86 for cur in global_pal: | |
87 curdist = color_dist(gpixel, cur) | |
88 if curdist < bestdist: | |
89 bestdist = curdist | |
90 bestpal = global_pal[cur] | |
91 for cur in line_pals[y]: | |
92 curdist = color_dist(gpixel, cur) | |
93 if curdist < bestdist: | |
94 bestdist = curdist | |
95 bestpal = line_pals[y][cur] | |
96 gpixels.append(bestpal) | |
97 else: | |
98 gpixels.append(0) | |
99 x += 1 | |
100 if width % 8: | |
101 for i in xrange(0, 8-(width%8)): | |
102 gpixels.append(0) | |
103 width += 8-(width%8) | |
104 if height % 8: | |
105 for y in xrange(0, 8-(height%8)): | |
106 for x in xrange(0, width): | |
107 gpixels.append(0) | |
108 height += 8-(height%8) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
109 |
3 | 110 return (width, height, gpixels) |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
111 |
3 | 112 def appendword(b, word): |
113 b.append(word >> 8) | |
114 b.append(word & 0xff) | |
115 | |
116 def to_tiles(palpix): | |
117 (width, height, pixels) = palpix | |
118 b = bytearray() | |
119 cwidth = width/8 | |
120 cheight = height/8 | |
121 words = len(pixels)/4 | |
122 appendword(b, words) | |
123 appendword(b, cwidth) | |
124 appendword(b, cheight) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
125 |
3 | 126 for cy in xrange(0, cheight): |
127 ystart = cy*8*width | |
128 for cx in xrange(0, cwidth): | |
129 startoff = (cx*8) + ystart | |
130 for row in xrange(0, 8): | |
131 rowoff = startoff + row*width | |
132 for bytecol in xrange(0, 4): | |
133 boff = bytecol * 2 + rowoff | |
134 #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight | |
135 #print 'pixels[boff]:', pixels[boff] | |
136 b.append(pixels[boff] << 4 | pixels[boff+1]) | |
137 return b | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
138 |
3 | 139 def add_pal_entries(tiles, pal): |
140 (global_pal, line_pals) = pal | |
141 pal_list = [()] * len(global_pal) | |
142 for entry in global_pal: | |
143 pal_list[global_pal[entry]] = entry | |
144 for entry in pal_list: | |
145 (R, G, B) = entry | |
146 tiles.append(B) | |
147 tiles.append(G << 4 | R) | |
148 for line in line_pals: | |
149 pal_list = [()] * len(line) | |
150 for entry in line: | |
151 pal_list[line[entry]] = entry | |
152 for entry in pal_list: | |
153 (R, G, B) = entry | |
154 tiles.append(B) | |
155 tiles.append(G << 4 | R) | |
156 | |
157 def getcolor(tiles, fixedpal, linepals, width, x, y): | |
158 celly = y/8 | |
159 cellx = x/8 | |
160 resty = y%8 | |
161 restx = x%8 | |
162 cellwidth = width / 8 | |
163 offset = celly * 32 * cellwidth + resty * 4 + cellx * 32 + restx / 2 | |
164 if restx & 1: | |
165 palidx = tiles[offset] & 0xF | |
166 else: | |
167 palidx = (tiles[offset] >> 4) & 0xF | |
168 if palidx < len(fixedpal): | |
169 return fixedpal[palidx] | |
170 return linepals[y][palidx - len(fixedpal)] | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
171 |
3 | 172 def to_pixels(tiles, im): |
173 (_, width, height), tiles, (fixedpal, linepals) = tiles | |
174 for y in xrange(0, height): | |
175 for x in xrange(0, width): | |
176 color = getcolor(tiles, fixedpal, linepals, width, x, y) | |
177 im.putpixel((x,y), color) | |
178 return im | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
179 |
3 | 180 def expand_pal(pal): |
181 def expand_pal_int(pal): | |
182 return ((pal << 4) & 0xE0, pal & 0xE0, (pal >> 4) & 0xE0) | |
183 fixedpal, linepals = pal | |
184 fixedpal = [expand_pal_int(color) for color in fixedpal] | |
185 linepals = [[expand_pal_int(color) for color in linepal] for linepal in linepals] | |
186 return (fixedpal, linepals) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
187 |
3 | 188 def open_tiles(name): |
189 from struct import unpack, unpack_from | |
190 f = open(name, 'rb') | |
191 header = f.read(6) | |
192 words,width,height = unpack('>HHH', header) | |
193 width *= 8 | |
194 height *= 8 | |
195 meta = (words, width, height) | |
196 pixels = bytearray(f.read(words * 2)) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
197 numfixed = 8 |
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
198 numdynamic = 8 |
3 | 199 fixedpalb = f.read(numfixed*2) |
200 fixedpal = [] | |
201 for offset in xrange(0, numfixed*2, 2): | |
202 color, = unpack_from('>H', fixedpalb, offset) | |
203 fixedpal.append(color) | |
204 linepals = [] | |
205 linepalsize = numdynamic * height * 2 | |
206 linepalb = f.read(linepalsize) | |
207 for baseoffset in xrange(0, linepalsize, numdynamic * 2): | |
208 linepal = [] | |
209 for offset in xrange(baseoffset, baseoffset + numdynamic * 2, 2): | |
210 color, = unpack_from('>H', linepalb, offset) | |
211 linepal.append(color) | |
212 linepals.append(linepal) | |
213 return (meta, pixels, (fixedpal, linepals)) | |
214 | |
215 def main(argv): | |
216 if len(argv) < 3: | |
217 print "Not enough arguments" | |
218 return | |
219 fname = argv[1] | |
220 tiles = open_tiles(fname) | |
221 im = Image.new('RGB', (tiles[0][1], tiles[0][2])) | |
222 tiles = (tiles[0], tiles[1], expand_pal(tiles[2])) | |
223 to_pixels(tiles, im) | |
224 out = open(argv[2], 'wb') | |
225 im.save(out) | |
6
3148b6389042
Set dynamic colors to 8 in tiles2img
Mike Pavone <pavone@retrodev.com>
parents:
3
diff
changeset
|
226 |
3 | 227 if __name__ == '__main__': |
228 import sys | |
229 main(sys.argv) |