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)