#!/usr/bin/env python import os import re import struct from collections import defaultdict from PIL import Image ushrtmax = (1<<16)-1 # greedy RLE # for each pixel, test which encoding results in the smaller size, then apply # that encoding and look at the next pixel after the encoded chunk def encode1(im): pixels = im.load() w,h = im.size result = [] # these function return a tuple of the compressed string and the amount of # pixels compressed def rle_comp(x,y): # find all pixels after the first one with the same color color = pixels[x,y] if color == 0xff: # this color can't be run length encoded return raw_comp(x,y) else: count = 1 for x in range(x+1,w): if pixels[x,y] == color and count < 255: count += 1 else: break return (struct.pack(" rawl: r += rlec x += rlel else: r += rawc x += rawl result.append(r) return result def encode3(im): pixels = im.load() w,h = im.size result = [] for y in range(h): r = '' if pixels[0,y] < 8: colors = pixels[0,y] count = 1 else: colors = [pixels[0,y]] count = 0 for x in range(1,w): color = pixels[x,y] if count > 0: # rle was started if color == colors and count < 32: # same color again, increase count count+=1 else: # either new color or maximum length reached, so write current one r+=struct.pack(" 31: # new rle color, or maximum length reached so write current non rle r+=struct.pack(" 0: # write rle r+=struct.pack(">5)+1)<<5 rm = lm+w im = im.crop((lm,tm,rm,bm)) if im.mode != 'P': print "input images must have a palette" return False cursig =(t,p,fw,fh,im.getpalette(),fmt) if not sig: sig = cursig else: if sig != cursig: print "sigs must match - got:" print sig print cursig return False if len(fn) > 9: print "filename can't be longer than 9 bytes" return False if fmt == 0: data = ''.join([chr(i) for i in list(im.getdata())]) elif fmt == 1: data = encode1(im) elif fmt == 2: data = encode3(im) elif fmt == 3: data = encode3(im) else: print "unknown format: %d"%fmt return False infiles[bid].append((im,t,p,j,fn,lm,tm,fmt,data)) if len(infiles) == 0: print "no input files detected" return False # check if j values for all bids are correct and sort them in j order in the process for bid in infiles: infiles[bid].sort(key=lambda t: t[3]) for k,(_,_,_,j,_,_,_,_,_) in enumerate(infiles[bid]): if k != j: print "incorrect j value %d for bid %d should be %d"%(j,bid,k) t,p,fw,fh,pal,fmt = cursig outname = os.path.join(outdir,p)+".def" print "writing to %s"%outname outf = open(outname, "w+") # write the header # full width and height are not used and not the same for all frames # in some defs, so just putting the last known value outf.write(struct.pack(" ushrtmax: print "exceeding max ushort value: %d"%offs return False outf.write(struct.pack(" ushrtmax: print "exceeding max ushort value: %d"%offs return False lineoffs.append(offs) lineoffs.extend([0 for i in range(w/32-1)]) acc += len(d) outf.write(struct.pack("<"+"H"*(w/32)*h, *lineoffs)) for i in data: outf.write(i) return True if __name__ == '__main__': import sys if len(sys.argv) != 3: print "usage: %s indir outdir"%sys.argv[0] exit(1) ret = makedef(sys.argv[1], sys.argv[2]) exit(0 if ret else 1)