diff tiles2img.py @ 3:97ec271a513f

Bunch of changes
author Mike Pavone <pavone@retrodev.com>
date Mon, 02 Sep 2013 21:22:47 -0700
parents
children 3148b6389042
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tiles2img.py	Mon Sep 02 21:22:47 2013 -0700
@@ -0,0 +1,229 @@
+#!/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 = 12
+	numdynamic = 4
+	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)