format3 is actually stored in 32 pixel chunks, different from format2
This commit is contained in:
parent
5b45233b5e
commit
2ee206c2d5
2 changed files with 108 additions and 93 deletions
|
@ -94,14 +94,14 @@ def extract_def(infile,outdir,shred=True):
|
||||||
totalrowlength+=length
|
totalrowlength+=length
|
||||||
elif fmt == 2:
|
elif fmt == 2:
|
||||||
lineoffs = struct.unpack("<%dH"%h, f.read(2*h))
|
lineoffs = struct.unpack("<%dH"%h, f.read(2*h))
|
||||||
# unknown
|
_,_ = struct.unpack("<BB", f.read(2)) # unknown
|
||||||
_,_ = struct.unpack("<BB", f.read(2))
|
|
||||||
for lineoff in lineoffs:
|
for lineoff in lineoffs:
|
||||||
if f.tell() != offs+32+lineoff:
|
if f.tell() != offs+32+lineoff:
|
||||||
print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+lineoff)
|
print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+lineoff)
|
||||||
f.seek(offs+32+lineoff)
|
f.seek(offs+32+lineoff)
|
||||||
totalrowlength=0
|
totalrowlength=0
|
||||||
while totalrowlength<w:
|
while totalrowlength<w:
|
||||||
|
print f.tell()-32-offs
|
||||||
segment, = struct.unpack("<B", f.read(1))
|
segment, = struct.unpack("<B", f.read(1))
|
||||||
code = segment>>5
|
code = segment>>5
|
||||||
length = (segment&0x1f)+1
|
length = (segment&0x1f)+1
|
||||||
|
@ -111,24 +111,25 @@ def extract_def(infile,outdir,shred=True):
|
||||||
pixeldata += length*chr(code)
|
pixeldata += length*chr(code)
|
||||||
totalrowlength+=length
|
totalrowlength+=length
|
||||||
elif fmt == 3:
|
elif fmt == 3:
|
||||||
# the first unsigned short in every w/16 byte block is the
|
# each row is split into 32 byte long blocks which are individually encoded
|
||||||
# offset we want - the others have an unknown function
|
# two bytes store the offset for each block per line
|
||||||
lineoffs = [struct.unpack("<"+"H"*(w/32), f.read(w/16))[0] for i in range(h)]
|
lineoffs = [struct.unpack("<"+"H"*(w/32), f.read(w/16)) for i in range(h)]
|
||||||
|
|
||||||
for lineoff in lineoffs:
|
for lineoff in lineoffs:
|
||||||
if f.tell() != offs+32+lineoff:
|
for i in lineoff:
|
||||||
print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+lineoff)
|
if f.tell() != offs+32+i:
|
||||||
f.seek(offs+32+lineoff)
|
print "unexpected offset: %d, expected %d"%(f.tell(),offs+32+i)
|
||||||
totalrowlength=0
|
f.seek(offs+32+i)
|
||||||
while totalrowlength<w:
|
totalblocklength=0
|
||||||
segment, = struct.unpack("<B", f.read(1))
|
while totalblocklength<32:
|
||||||
code = segment>>5
|
segment, = struct.unpack("<B", f.read(1))
|
||||||
length = (segment&0x1f)+1
|
code = segment>>5
|
||||||
if code == 7: # raw data
|
length = (segment&0x1f)+1
|
||||||
pixeldata += f.read(length)
|
if code == 7: # raw data
|
||||||
else: # rle
|
pixeldata += f.read(length)
|
||||||
pixeldata += length*chr(code)
|
else: # rle
|
||||||
totalrowlength+=length
|
pixeldata += length*chr(code)
|
||||||
|
totalblocklength+=length
|
||||||
else:
|
else:
|
||||||
print "unknown format: %d"%fmt
|
print "unknown format: %d"%fmt
|
||||||
return False
|
return False
|
||||||
|
|
164
makedef.py
164
makedef.py
|
@ -7,8 +7,11 @@ from collections import defaultdict
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
ushrtmax = (1<<16)-1
|
ushrtmax = (1<<16)-1
|
||||||
|
|
||||||
|
def encode0(im):
|
||||||
|
return ''.join([chr(i) for i in list(im.getdata())])
|
||||||
|
|
||||||
# greedy RLE
|
# 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
|
# that encoding and look at the next pixel after the encoded chunk
|
||||||
def encode1(im):
|
def encode1(im):
|
||||||
pixels = im.load()
|
pixels = im.load()
|
||||||
|
@ -56,62 +59,82 @@ def encode1(im):
|
||||||
result.append(r)
|
result.append(r)
|
||||||
return result
|
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("<B", (colors<<5) | (count-1))
|
||||||
|
if color < 7:
|
||||||
|
# new rle color
|
||||||
|
colors = color
|
||||||
|
count = 1
|
||||||
|
else:
|
||||||
|
# new non rle color
|
||||||
|
colors = [color]
|
||||||
|
count = 0
|
||||||
|
else:
|
||||||
|
# non rle was started
|
||||||
|
if color < 7 or len(colors) > 31:
|
||||||
|
# new rle color, or maximum length reached so write current non rle
|
||||||
|
r+=struct.pack("<B", (7<<5) | (len(colors)-1))
|
||||||
|
r+=struct.pack("<%dB"%len(colors), *colors)
|
||||||
|
if color < 7:
|
||||||
|
colors = color
|
||||||
|
count = 1
|
||||||
|
else:
|
||||||
|
colors = [color]
|
||||||
|
count = 0
|
||||||
|
else:
|
||||||
|
# new non rle color, so append it to current
|
||||||
|
colors.append(color)
|
||||||
|
# write last color
|
||||||
|
if count > 0:
|
||||||
|
# write rle
|
||||||
|
r+=struct.pack("<B", (colors<<5) | (count-1))
|
||||||
|
else:
|
||||||
|
# write non rle
|
||||||
|
r+=struct.pack("<B", (7<<5) | (len(colors)-1))
|
||||||
|
r+=struct.pack("<%dB"%len(colors), *colors)
|
||||||
|
return r
|
||||||
|
|
||||||
|
# this is like encode3 but a line is not split into 32 pixel chuncks
|
||||||
|
# the reason for this might just be that format 2 images are always 32 pixel wide
|
||||||
|
def encode2(im):
|
||||||
|
pixels = im.load()
|
||||||
|
w,h = im.size
|
||||||
|
result = []
|
||||||
|
for y in range(h):
|
||||||
|
result.append(encode23chunk(0,w,pixels,y))
|
||||||
|
return result
|
||||||
|
|
||||||
|
# this is like encode2 but limited to only encoding blocks of 32 pixels at a time
|
||||||
def encode3(im):
|
def encode3(im):
|
||||||
pixels = im.load()
|
pixels = im.load()
|
||||||
w,h = im.size
|
w,h = im.size
|
||||||
result = []
|
result = []
|
||||||
for y in range(h):
|
for y in range(h):
|
||||||
r = ''
|
res = []
|
||||||
if pixels[0,y] < 8:
|
# encode each row in 32 pixel blocks
|
||||||
colors = pixels[0,y]
|
for i in range(w/32):
|
||||||
count = 1
|
res.append(encode23chunk(i*32, (i+1)*32, pixels, y))
|
||||||
else:
|
result.append(res)
|
||||||
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("<B", (colors<<5) | (count-1))
|
|
||||||
if color < 7:
|
|
||||||
# new rle color
|
|
||||||
colors = color
|
|
||||||
count = 1
|
|
||||||
else:
|
|
||||||
# new non rle color
|
|
||||||
colors = [color]
|
|
||||||
count = 0
|
|
||||||
else:
|
|
||||||
# non rle was started
|
|
||||||
if color < 7 or len(colors) > 31:
|
|
||||||
# new rle color, or maximum length reached so write current non rle
|
|
||||||
r+=struct.pack("<B", (7<<5) | (len(colors)-1))
|
|
||||||
r+=struct.pack("<%dB"%len(colors), *colors)
|
|
||||||
if color < 7:
|
|
||||||
colors = color
|
|
||||||
count = 1
|
|
||||||
else:
|
|
||||||
colors = [color]
|
|
||||||
count = 0
|
|
||||||
else:
|
|
||||||
# new non rle color, so append it to current
|
|
||||||
colors.append(color)
|
|
||||||
# write last color
|
|
||||||
if count > 0:
|
|
||||||
# write rle
|
|
||||||
r+=struct.pack("<B", (colors<<5) | (count-1))
|
|
||||||
else:
|
|
||||||
# write non rle
|
|
||||||
r+=struct.pack("<B", (7<<5) | (len(colors)-1))
|
|
||||||
r+=struct.pack("<%dB"%len(colors), *colors)
|
|
||||||
result.append(r)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
fmtencoders = [encode0,encode1,encode2,encode3]
|
||||||
|
|
||||||
def makedef(indir, outdir):
|
def makedef(indir, outdir):
|
||||||
infiles = defaultdict(list)
|
infiles = defaultdict(list)
|
||||||
sig = None
|
sig = None
|
||||||
|
@ -150,17 +173,7 @@ def makedef(indir, outdir):
|
||||||
if len(fn) > 9:
|
if len(fn) > 9:
|
||||||
print "filename can't be longer than 9 bytes"
|
print "filename can't be longer than 9 bytes"
|
||||||
return False
|
return False
|
||||||
if fmt == 0:
|
data = fmtencoders[fmt](im)
|
||||||
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))
|
infiles[bid].append((im,t,p,j,fn,lm,tm,fmt,data))
|
||||||
|
|
||||||
if len(infiles) == 0:
|
if len(infiles) == 0:
|
||||||
|
@ -213,7 +226,7 @@ def makedef(indir, outdir):
|
||||||
curoffset += 32+2*h+2+sum(len(d) for d in data)
|
curoffset += 32+2*h+2+sum(len(d) for d in data)
|
||||||
elif fmt == 3:
|
elif fmt == 3:
|
||||||
# width/16 bytes per line as offset header
|
# 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 bid,l in infiles.items():
|
||||||
for im,_,p,j,_,lm,tm,fmt,data in l:
|
for im,_,p,j,_,lm,tm,fmt,data in l:
|
||||||
|
@ -252,26 +265,27 @@ def makedef(indir, outdir):
|
||||||
lineoffs.append(offs)
|
lineoffs.append(offs)
|
||||||
acc += len(d)
|
acc += len(d)
|
||||||
outf.write(struct.pack("<%dH"%h, *lineoffs))
|
outf.write(struct.pack("<%dH"%h, *lineoffs))
|
||||||
outf.write(struct.pack("<BB", 0, 0)) # unknown function
|
outf.write(struct.pack("<BB", 0, 0)) # unknown meaning
|
||||||
for i in data:
|
for i in data:
|
||||||
outf.write(i)
|
outf.write(i)
|
||||||
elif fmt == 3:
|
elif fmt == 3:
|
||||||
s = (w/16)*h+sum(len(d) for d in data)
|
s = (w/16)*h+sum(sum([len(e) for e in d]) for d in data)
|
||||||
outf.write(struct.pack("<IIIIIIii",s,fmt,fw,fh,w,h,lm,tm))
|
outf.write(struct.pack("<IIIIIIii",s,fmt,fw,fh,w,h,lm,tm))
|
||||||
# store the same value in all w/16 blocks per line
|
# store the offsets for all 32 pixel blocks
|
||||||
lineoffs = []
|
|
||||||
acc = 0
|
acc = 0
|
||||||
|
lineoffs = []
|
||||||
for d in data:
|
for d in data:
|
||||||
offs = acc+(w/16)*h
|
for e in d:
|
||||||
if offs > ushrtmax:
|
offs = acc+(w/16)*h
|
||||||
print "exceeding max ushort value: %d"%offs
|
if offs > ushrtmax:
|
||||||
return False
|
print "exceeding max ushort value: %d"%offs
|
||||||
lineoffs.append(offs)
|
return False
|
||||||
lineoffs.extend([0 for i in range(w/32-1)])
|
lineoffs.append(offs)
|
||||||
acc += len(d)
|
acc += len(e)
|
||||||
outf.write(struct.pack("<"+"H"*(w/32)*h, *lineoffs))
|
outf.write(struct.pack("<"+"H"*(w/32)*h, *lineoffs))
|
||||||
for i in data:
|
for d in data: # line
|
||||||
outf.write(i)
|
for e in d: # 32 pixel block
|
||||||
|
outf.write(e)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in a new issue