3
|
1 #!/usr/bin/env python
|
|
2 from PIL import Image
|
|
3
|
|
4 def gchannel(Val):
|
|
5 return (Val >> 4) & 0xE
|
|
6
|
|
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
|
|
29
|
|
30 def totiles(im, palette):
|
|
31 pass
|
|
32
|
|
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, max_global, max_line)
|
|
52
|
|
53 def color_dist(a, b):
|
|
54 (ra, ga, ba) = a
|
|
55 (rb, gb, bb) = b
|
|
56 return (ra-rb)**2 + (ga-gb)**2 + (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)
|
|
109
|
|
110 return (width, height, gpixels)
|
|
111
|
|
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)
|
|
125
|
|
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
|
|
138
|
|
139 def add_pal_entries(tiles, pal):
|
|
140 (global_pal, line_pals, max_global, max_line) = pal
|
|
141 pal_list = [(0, 0, 0)] * max_global
|
|
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 = [(0, 0, 0)] * max_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
|
|
158
|
|
159 def main(argv):
|
|
160 if len(argv) < 3:
|
|
161 print "Not enough arguments"
|
|
162 return
|
|
163 fname = argv[1]
|
|
164 im = Image.open(fname)
|
|
165 pal = make_palette(im, threshold, 8, 8)
|
|
166 palpix = trans_image(im, threshold, pal)
|
|
167 tiles = to_tiles(palpix)
|
|
168 bits = add_pal_entries(tiles, pal)
|
|
169 out = open(argv[2], 'wb')
|
|
170 out.write(tiles)
|
|
171
|
|
172 if __name__ == '__main__':
|
|
173 import sys
|
|
174 main(sys.argv)
|