Mercurial > repos > blastem
comparison img2tiles.py @ 2050:dbbf0100f249
Update img2tyles to use Python 3
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 31 Dec 2021 12:27:14 -0800 |
parents | 40703069bb68 |
children |
comparison
equal
deleted
inserted
replaced
2044:460e14497120 | 2050:dbbf0100f249 |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python3 |
2 from PIL import Image | 2 from PIL import Image |
3 | 3 |
4 def gchannel(Val): | 4 def gchannel(Val): |
5 return (Val >> 4) & 0xE | 5 return (Val >> 4) & 0xE |
6 | 6 |
66 else: | 66 else: |
67 transparent = True | 67 transparent = True |
68 glist = [(gencolors[color][0] * gencolors[color][1], color) for color in gencolors] | 68 glist = [(gencolors[color][0] * gencolors[color][1], color) for color in gencolors] |
69 glist.sort() | 69 glist.sort() |
70 glist.reverse() | 70 glist.reverse() |
71 | 71 |
72 return glist | 72 return glist |
73 | 73 |
74 def make_palette(im, trans_thresh, max_global, max_line): | 74 def make_palette(im, trans_thresh, max_global, max_line): |
75 pixels = im.getdata() | 75 pixels = im.getdata() |
76 (width, height) = im.size | 76 (width, height) = im.size |
77 colors = get_color_info(im, pixels, xrange(0, height * width), trans_thresh) | 77 colors = get_color_info(im, pixels, range(0, height * width), trans_thresh) |
78 print len(colors), 'distinct 9-bit colors in image' | 78 print(len(colors), 'distinct 9-bit colors in image') |
79 glob_pal = {} | 79 glob_pal = {} |
80 print 'Static Palette:' | 80 print('Static Palette:') |
81 while len(glob_pal) < max_global and len(colors): | 81 while len(glob_pal) < max_global and len(colors): |
82 idx = len(glob_pal) | 82 idx = len(glob_pal) |
83 (count, color) = colors[0] | 83 (count, color) = colors[0] |
84 print str(idx) + ':', color | 84 print(str(idx) + ':', color) |
85 glob_pal[color] = idx | 85 glob_pal[color] = idx |
86 colors = get_color_info_both(im, pixels, xrange(0, height * width), trans_thresh, glob_pal) | 86 colors = get_color_info_both(im, pixels, range(0, height * width), trans_thresh, glob_pal) |
87 line_pals = [] | 87 line_pals = [] |
88 if max_global < len(colors): | 88 if max_global < len(colors): |
89 for line in xrange(0, height): | 89 for line in range(0, height): |
90 linestart = line * width | 90 linestart = line * width |
91 if len(glob_pal): | 91 if len(glob_pal): |
92 linecolors = get_color_info_both(im, pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal) | 92 linecolors = get_color_info_both(im, pixels, range(linestart, linestart+width), trans_thresh, glob_pal) |
93 else: | 93 else: |
94 linecolors = get_color_info(im, pixels, xrange(linestart, linestart+width), trans_thresh) | 94 linecolors = get_color_info(im, pixels, range(linestart, linestart+width), trans_thresh) |
95 line_pal = {} | 95 line_pal = {} |
96 while len(line_pal) < max_line and len(linecolors): | 96 while len(line_pal) < max_line and len(linecolors): |
97 (score, color) = linecolors[0] | 97 (score, color) = linecolors[0] |
98 line_pal[color] = len(line_pal) + max_global | 98 line_pal[color] = len(line_pal) + max_global |
99 if len(line_pal) < max_line: | 99 if len(line_pal) < max_line: |
100 combo = dict(glob_pal) | 100 combo = dict(glob_pal) |
101 for color in line_pal: | 101 for color in line_pal: |
102 combo[color] = line_pal[color] | 102 combo[color] = line_pal[color] |
103 linecolors = get_color_info_both(im, pixels, xrange(linestart, linestart+width), trans_thresh, combo) | 103 linecolors = get_color_info_both(im, pixels, range(linestart, linestart+width), trans_thresh, combo) |
104 #for idx in xrange(0, min(max_line, len(linecolors))): | 104 #for idx in range(0, min(max_line, len(linecolors))): |
105 # (count, color) = linecolors[idx] | 105 # (count, color) = linecolors[idx] |
106 # line_pal[color] = idx + max_global | 106 # line_pal[color] = idx + max_global |
107 line_pals.append(line_pal) | 107 line_pals.append(line_pal) |
108 return (glob_pal, line_pals, max_global, max_line) | 108 return (glob_pal, line_pals, max_global, max_line) |
109 | 109 |
114 | 114 |
115 def best_match(gpixel, pals): | 115 def best_match(gpixel, pals): |
116 bestdist = color_dist((0,0,0), (15, 15, 15)) | 116 bestdist = color_dist((0,0,0), (15, 15, 15)) |
117 bestpalidx = 0 | 117 bestpalidx = 0 |
118 bestcolor = (0,0,0) | 118 bestcolor = (0,0,0) |
119 for i in xrange(0, len(pals)): | 119 for i in range(0, len(pals)): |
120 pal = pals[i] | 120 pal = pals[i] |
121 for cur in pal: | 121 for cur in pal: |
122 curdist = color_dist(gpixel, cur) | 122 curdist = color_dist(gpixel, cur) |
123 if curdist < bestdist: | 123 if curdist < bestdist: |
124 bestdist = curdist | 124 bestdist = curdist |
140 for pixel in pixels: | 140 for pixel in pixels: |
141 if x == width: | 141 if x == width: |
142 x = 0 | 142 x = 0 |
143 y += 1 | 143 y += 1 |
144 if width % 8 and not chunky: | 144 if width % 8 and not chunky: |
145 for i in xrange(0, 8-(width%8)): | 145 for i in range(0, 8-(width%8)): |
146 gpixels.append(0) | 146 gpixels.append(0) |
147 gpixel = get_gcolor(im, trans_thresh, color=pixel) | 147 gpixel = get_gcolor(im, trans_thresh, color=pixel) |
148 if type(gpixel) == tuple: | 148 if type(gpixel) == tuple: |
149 if gpixel in global_pal: | 149 if gpixel in global_pal: |
150 val = global_pal[gpixel] | 150 val = global_pal[gpixel] |
156 gpixels.append(offset+val) | 156 gpixels.append(offset+val) |
157 else: | 157 else: |
158 gpixels.append(gpixel) | 158 gpixels.append(gpixel) |
159 x += 1 | 159 x += 1 |
160 if width % 8 and not chunky: | 160 if width % 8 and not chunky: |
161 for i in xrange(0, 8-(width%8)): | 161 for i in range(0, 8-(width%8)): |
162 gpixels.append(0) | 162 gpixels.append(0) |
163 width += 8-(width%8) | 163 width += 8-(width%8) |
164 if height % 8 and not chunky: | 164 if height % 8 and not chunky: |
165 for y in xrange(0, 8-(height%8)): | 165 for y in range(0, 8-(height%8)): |
166 for x in xrange(0, width): | 166 for x in range(0, width): |
167 gpixels.append(0) | 167 gpixels.append(0) |
168 height += 8-(height%8) | 168 height += 8-(height%8) |
169 | 169 |
170 return (width, height, gpixels) | 170 return (width, height, gpixels) |
171 | 171 |
181 appendword(b, width) | 181 appendword(b, width) |
182 appendword(b, height) | 182 appendword(b, height) |
183 for pixel in pixels: | 183 for pixel in pixels: |
184 b.append(pixel) | 184 b.append(pixel) |
185 else: | 185 else: |
186 cwidth = width/8 | 186 cwidth = width//8 |
187 cheight = height/tile_height | 187 cheight = height//tile_height |
188 words = len(pixels)/4 | 188 words = len(pixels)//4 |
189 if not raw: | 189 if not raw: |
190 appendword(b, words) | 190 appendword(b, words) |
191 appendword(b, cwidth) | 191 appendword(b, cwidth) |
192 appendword(b, cheight) | 192 appendword(b, cheight) |
193 | 193 |
194 if sprite_order: | 194 if sprite_order: |
195 for cx in xrange(0, cwidth): | 195 for cx in range(0, cwidth): |
196 xstart = cx * 8 | 196 xstart = cx * 8 |
197 for cy in xrange(0, cheight): | 197 for cy in range(0, cheight): |
198 startoff = cy*tile_height*width + xstart | 198 startoff = cy*tile_height*width + xstart |
199 for row in xrange(0, tile_height): | 199 for row in range(0, tile_height): |
200 rowoff = startoff + row*width | 200 rowoff = startoff + row*width |
201 for bytecol in xrange(0, 4): | 201 for bytecol in range(0, 4): |
202 boff = bytecol * 2 + rowoff | 202 boff = bytecol * 2 + rowoff |
203 #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight | 203 #print('boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight) |
204 #print 'pixels[boff]:', pixels[boff] | 204 #print('pixels[boff]:', pixels[boff]) |
205 b.append(pixels[boff] << 4 | pixels[boff+1]) | 205 b.append(pixels[boff] << 4 | pixels[boff+1]) |
206 else: | 206 else: |
207 for cy in xrange(0, cheight): | 207 for cy in range(0, cheight): |
208 ystart = cy*tile_height*width | 208 ystart = cy*tile_height*width |
209 for cx in xrange(0, cwidth): | 209 for cx in range(0, cwidth): |
210 startoff = (cx*8) + ystart | 210 startoff = (cx*8) + ystart |
211 for row in xrange(0, tile_height): | 211 for row in range(0, tile_height): |
212 rowoff = startoff + row*width | 212 rowoff = startoff + row*width |
213 for bytecol in xrange(0, 4): | 213 for bytecol in range(0, 4): |
214 boff = bytecol * 2 + rowoff | 214 boff = bytecol * 2 + rowoff |
215 #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight | 215 #print('boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight) |
216 #print 'pixels[boff]:', pixels[boff] | 216 #print('pixels[boff]:', pixels[boff]) |
217 b.append(pixels[boff] << 4 | pixels[boff+1]) | 217 b.append(pixels[boff] << 4 | pixels[boff+1]) |
218 return b | 218 return b |
219 | 219 |
220 def add_pal_entries(tiles, pal): | 220 def add_pal_entries(tiles, pal): |
221 (global_pal, line_pals, max_global, max_line) = pal | 221 (global_pal, line_pals, max_global, max_line) = pal |
245 omit_pal = raw = chunky = False | 245 omit_pal = raw = chunky = False |
246 expect_option = None | 246 expect_option = None |
247 options = {} | 247 options = {} |
248 tile_height = 8 | 248 tile_height = 8 |
249 sprite_order = False | 249 sprite_order = False |
250 for i in xrange(1, len(argv)): | 250 for i in range(1, len(argv)): |
251 if argv[i].startswith('-'): | 251 if argv[i].startswith('-'): |
252 if argv[i] == '-r': | 252 if argv[i] == '-r': |
253 raw = True | 253 raw = True |
254 elif argv[i] == '-p': | 254 elif argv[i] == '-p': |
255 omit_pal = True | 255 omit_pal = True |
260 elif argv[i] == '-i': | 260 elif argv[i] == '-i': |
261 tile_height = 16 | 261 tile_height = 16 |
262 elif argv[i] == '-s' or argv[i] == '--spec': | 262 elif argv[i] == '-s' or argv[i] == '--spec': |
263 expect_option = 'specfile' | 263 expect_option = 'specfile' |
264 else: | 264 else: |
265 print 'Unrecognized switch', argv[i] | 265 print('Unrecognized switch', argv[i]) |
266 return | 266 return |
267 elif not expect_option is None: | 267 elif not expect_option is None: |
268 options[expect_option] = argv[i] | 268 options[expect_option] = argv[i] |
269 expect_option = None | 269 expect_option = None |
270 else: | 270 else: |
271 posargs.append(argv[i]) | 271 posargs.append(argv[i]) |
272 if len(posargs) < 2 and not ('specfile' in options and len(posargs) >= 1): | 272 if len(posargs) < 2 and not ('specfile' in options and len(posargs) >= 1): |
273 print "Usage: img2tiles.py [OPTIONS] infile outfile [STATIC_COLORS [DYNAMIC_COLORS]]" | 273 print("Usage: img2tiles.py [OPTIONS] infile outfile [STATIC_COLORS [DYNAMIC_COLORS]]") |
274 return | 274 return |
275 if 'specfile' in options: | 275 if 'specfile' in options: |
276 props = open(options['specfile']).read().strip().split(',') | 276 props = open(options['specfile']).read().strip().split(',') |
277 fname,static_colors,dynamic_colors = props[0:3] | 277 fname,static_colors,dynamic_colors = props[0:3] |
278 for prop in props[3:]: | 278 for prop in props[3:]: |
298 static_colors = int(posargs[2]) | 298 static_colors = int(posargs[2]) |
299 dynamic_colors = 16-static_colors | 299 dynamic_colors = 16-static_colors |
300 if len(posargs) > 3: | 300 if len(posargs) > 3: |
301 dynamic_colors = int(posargs[3]) | 301 dynamic_colors = int(posargs[3]) |
302 if dynamic_colors + static_colors > 16: | 302 if dynamic_colors + static_colors > 16: |
303 print "No more than 16 combined dynamic and static colors are allowed" | 303 print("No more than 16 combined dynamic and static colors are allowed") |
304 return | 304 return |
305 im = Image.open(fname) | 305 im = Image.open(fname) |
306 pal = make_palette(im, threshold, static_colors, dynamic_colors) | 306 pal = make_palette(im, threshold, static_colors, dynamic_colors) |
307 palpix = trans_image(im, threshold, pal, chunky) | 307 palpix = trans_image(im, threshold, pal, chunky) |
308 tiles = to_tiles(palpix, raw, chunky, tile_height, sprite_order) | 308 tiles = to_tiles(palpix, raw, chunky, tile_height, sprite_order) |