Mercurial > repos > ghero
view 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 |
line wrap: on
line source
#!/usr/bin/env python from PIL import Image def gchannel(Val): return (Val >> 4) & 0xE threshold = 127 def get_color_info(pixels, rng, threshold, exclude={}): gencolors = {} A = 255 for idx in rng: color = pixels[idx] if len(color) == 4: (R, G, B, A) = color else: (R, G, B) = color if A > threshold: gcolor = (gchannel(R), gchannel(G), gchannel(B)) if not gcolor in exclude: if gcolor in gencolors: gencolors[gcolor] += 1 else: gencolors[gcolor] = 1 glist = [(gencolors[color], color) for color in gencolors] glist.sort() glist.reverse() return glist def totiles(im, palette): pass def make_palette(im, trans_thresh, max_global, max_line): pixels = im.getdata() (width, height) = im.size colors = get_color_info(pixels, xrange(0, height * width), trans_thresh) glob_pal = {} for idx in xrange(0, min(max_global, len(colors))): (count, color) = colors[idx] glob_pal[color] = idx line_pals = [] if max_global < len(colors): for line in xrange(0, height): linestart = line * width linecolors = get_color_info(pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal) line_pal = {} for idx in xrange(0, min(max_line, len(linecolors))): (count, color) = linecolors[idx] line_pal[color] = idx line_pals.append(line_pal) return (glob_pal, line_pals) def color_dist(a, b): (ra, ga, ba) = a (rb, gb, bb) = b return abs(ra-rb)**2 + abs(ga-gb)**2 + abs(ba-bb)**2 def trans_image(im, trans_thresh, pal): (global_pal, line_pals) = pal pixels = im.getdata() (width, height) = im.size gpixels = [] A = 255 x = 0 y = 0 for pixel in pixels: if x == width: x = 0 y += 1 if width % 8: for i in xrange(0, 8-(width%8)): gpixels.append(0) if len(pixel) == 4: (R, G, B, A) = pixel else: (R, G, B) = pixel if A > trans_thresh: gpixel = (gchannel(R), gchannel(G), gchannel(B)) if gpixel in global_pal: gpixels.append(global_pal[gpixel]) elif gpixel in line_pals[y]: gpixels.append(line_pals[y][gpixel] + len(global_pal)) else: bestdist = color_dist((0,0,0), (15, 15, 15)) bestpal = 0 for cur in global_pal: curdist = color_dist(gpixel, cur) if curdist < bestdist: bestdist = curdist bestpal = global_pal[cur] for cur in line_pals[y]: curdist = color_dist(gpixel, cur) if curdist < bestdist: bestdist = curdist bestpal = line_pals[y][cur] gpixels.append(bestpal) else: gpixels.append(0) x += 1 if width % 8: for i in xrange(0, 8-(width%8)): gpixels.append(0) width += 8-(width%8) if height % 8: for y in xrange(0, 8-(height%8)): for x in xrange(0, width): gpixels.append(0) height += 8-(height%8) return (width, height, gpixels) def appendword(b, word): b.append(word >> 8) b.append(word & 0xff) def to_tiles(palpix): (width, height, pixels) = palpix b = bytearray() cwidth = width/8 cheight = height/8 words = len(pixels)/4 appendword(b, words) appendword(b, cwidth) appendword(b, cheight) for cy in xrange(0, cheight): ystart = cy*8*width for cx in xrange(0, cwidth): startoff = (cx*8) + ystart for row in xrange(0, 8): rowoff = startoff + row*width for bytecol in xrange(0, 4): boff = bytecol * 2 + rowoff #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight #print 'pixels[boff]:', pixels[boff] b.append(pixels[boff] << 4 | pixels[boff+1]) return b def add_pal_entries(tiles, pal): (global_pal, line_pals) = pal pal_list = [()] * len(global_pal) for entry in global_pal: pal_list[global_pal[entry]] = entry for entry in pal_list: (R, G, B) = entry tiles.append(B) tiles.append(G << 4 | R) for line in line_pals: pal_list = [()] * len(line) for entry in line: pal_list[line[entry]] = entry for entry in pal_list: (R, G, B) = entry tiles.append(B) tiles.append(G << 4 | R) def getcolor(tiles, fixedpal, linepals, width, x, y): celly = y/8 cellx = x/8 resty = y%8 restx = x%8 cellwidth = width / 8 offset = celly * 32 * cellwidth + resty * 4 + cellx * 32 + restx / 2 if restx & 1: palidx = tiles[offset] & 0xF else: palidx = (tiles[offset] >> 4) & 0xF if palidx < len(fixedpal): return fixedpal[palidx] return linepals[y][palidx - len(fixedpal)] def to_pixels(tiles, im): (_, width, height), tiles, (fixedpal, linepals) = tiles for y in xrange(0, height): for x in xrange(0, width): color = getcolor(tiles, fixedpal, linepals, width, x, y) im.putpixel((x,y), color) return im def expand_pal(pal): def expand_pal_int(pal): return ((pal << 4) & 0xE0, pal & 0xE0, (pal >> 4) & 0xE0) fixedpal, linepals = pal fixedpal = [expand_pal_int(color) for color in fixedpal] linepals = [[expand_pal_int(color) for color in linepal] for linepal in linepals] return (fixedpal, linepals) def open_tiles(name): from struct import unpack, unpack_from f = open(name, 'rb') header = f.read(6) words,width,height = unpack('>HHH', header) width *= 8 height *= 8 meta = (words, width, height) pixels = bytearray(f.read(words * 2)) numfixed = 8 numdynamic = 8 fixedpalb = f.read(numfixed*2) fixedpal = [] for offset in xrange(0, numfixed*2, 2): color, = unpack_from('>H', fixedpalb, offset) fixedpal.append(color) linepals = [] linepalsize = numdynamic * height * 2 linepalb = f.read(linepalsize) for baseoffset in xrange(0, linepalsize, numdynamic * 2): linepal = [] for offset in xrange(baseoffset, baseoffset + numdynamic * 2, 2): color, = unpack_from('>H', linepalb, offset) linepal.append(color) linepals.append(linepal) return (meta, pixels, (fixedpal, linepals)) def main(argv): if len(argv) < 3: print "Not enough arguments" return fname = argv[1] tiles = open_tiles(fname) im = Image.new('RGB', (tiles[0][1], tiles[0][2])) tiles = (tiles[0], tiles[1], expand_pal(tiles[2])) to_pixels(tiles, im) out = open(argv[2], 'wb') im.save(out) if __name__ == '__main__': import sys main(sys.argv)