diff --git a/defextract.py b/defextract.py index fb6f9c6..d3b20f2 100644 --- a/defextract.py +++ b/defextract.py @@ -94,14 +94,14 @@ def extract_def(infile,outdir,shred=True): totalrowlength+=length elif fmt == 2: lineoffs = struct.unpack("<%dH"%h, f.read(2*h)) - # unknown - _,_ = struct.unpack(">5 length = (segment&0x1f)+1 @@ -111,24 +111,25 @@ def extract_def(infile,outdir,shred=True): pixeldata += length*chr(code) totalrowlength+=length elif fmt == 3: - # the first unsigned short in every w/16 byte block is the - # offset we want - the others have an unknown function - lineoffs = [struct.unpack("<"+"H"*(w/32), f.read(w/16))[0] for i in range(h)] + # each row is split into 32 byte long blocks which are individually encoded + # two bytes store the offset for each block per line + lineoffs = [struct.unpack("<"+"H"*(w/32), f.read(w/16)) for i in range(h)] for lineoff in lineoffs: - if f.tell() != offs+32+lineoff: - print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+lineoff) - f.seek(offs+32+lineoff) - totalrowlength=0 - while totalrowlength>5 - length = (segment&0x1f)+1 - if code == 7: # raw data - pixeldata += f.read(length) - else: # rle - pixeldata += length*chr(code) - totalrowlength+=length + for i in lineoff: + if f.tell() != offs+32+i: + print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+i) + f.seek(offs+32+i) + totalblocklength=0 + while totalblocklength<32: + segment, = struct.unpack(">5 + length = (segment&0x1f)+1 + if code == 7: # raw data + pixeldata += f.read(length) + else: # rle + pixeldata += length*chr(code) + totalblocklength+=length else: print "unknown format: %d"%fmt return False diff --git a/makedef.py b/makedef.py index 5ca005b..2792f89 100644 --- a/makedef.py +++ b/makedef.py @@ -7,8 +7,11 @@ from collections import defaultdict from PIL import Image ushrtmax = (1<<16)-1 +def encode0(im): + return ''.join([chr(i) for i in list(im.getdata())]) + # greedy RLE -# for each pixel, test which encoding results in the smaller size, then apply +# for each pixel, test which encoding manages to encode most data, then apply # that encoding and look at the next pixel after the encoded chunk def encode1(im): pixels = im.load() @@ -56,62 +59,82 @@ def encode1(im): result.append(r) return result +def encode23chunk(s,e,pixels,y): + r = '' + if pixels[s,y] < 8: + colors = pixels[s,y] + count = 1 + else: + colors = [pixels[s,y]] + count = 0 + for x in range(s+1,e): + 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(" 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(" 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 + data = fmtencoders[fmt](im) infiles[bid].append((im,t,p,j,fn,lm,tm,fmt,data)) if len(infiles) == 0: @@ -213,7 +226,7 @@ def makedef(indir, outdir): curoffset += 32+2*h+2+sum(len(d) for d in data) elif fmt == 3: # width/16 bytes per line as offset header - curoffset += 32+(w/16)*h+sum(len(d) for d in data) + curoffset += 32+(w/16)*h+sum(sum([len(e) for e in d]) for d in data) for bid,l in infiles.items(): for im,_,p,j,_,lm,tm,fmt,data in l: @@ -252,26 +265,27 @@ def makedef(indir, outdir): lineoffs.append(offs) acc += len(d) outf.write(struct.pack("<%dH"%h, *lineoffs)) - 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) + for e in d: + offs = acc+(w/16)*h + if offs > ushrtmax: + print "exceeding max ushort value: %d"%offs + return False + lineoffs.append(offs) + acc += len(e) outf.write(struct.pack("<"+"H"*(w/32)*h, *lineoffs)) - for i in data: - outf.write(i) + for d in data: # line + for e in d: # 32 pixel block + outf.write(e) return True if __name__ == '__main__':