From 7c5377d29b80814db66fddebcc16057dc2ba00de Mon Sep 17 00:00:00 2001 From: josch Date: Sat, 22 Mar 2014 15:45:25 +0100 Subject: [PATCH] convert to and from RGBA images instead of palette based ones --- common.py | 27 ----------------- defextract.py | 41 +++++++++++++++++--------- definfo.py | 11 +++++-- lodextract.py | 2 -- makedef.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 110 insertions(+), 53 deletions(-) delete mode 100644 common.py diff --git a/common.py b/common.py deleted file mode 100644 index d702c58..0000000 --- a/common.py +++ /dev/null @@ -1,27 +0,0 @@ -import crcmod -import colorsys - -from PIL import ImageFont - -font = ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 34) - -def sanitize_filename(fname): - # find the first character outside range [32-126] - for i,c in enumerate(fname): - if ord(c) < 32 or ord(c) > 126: - break - return fname[:i] - -def get_complement(r,g,b): - r = r/255.0 - g = g/255.0 - b = b/255.0 - h,l,s = colorsys.rgb_to_hls(r, g, b) - if h > 0.5: - h -= 0.5 - else: - h += 0.5 - r,g,b = colorsys.hls_to_rgb(h, l, s) - return int(r*255), int(g*255), int(b*255) - -crc24_func = crcmod.mkCrcFun(0x1864CFBL) # polynomial from libgcrypt diff --git a/defextract.py b/defextract.py index 5c29614..afc32e6 100644 --- a/defextract.py +++ b/defextract.py @@ -25,13 +25,7 @@ from PIL import Image, ImageDraw from collections import defaultdict import os import json -from common import crc24_func, font, sanitize_filename - -def get_color(fname): - crc = crc24_func(fname) - # values 0-7 must not be used as they might represent transparency - # so we are left with 248 values - return 8+crc%248 +import numpy as np def extract_def(infile,outdir): f = open(infile) @@ -176,14 +170,33 @@ def extract_def(infile,outdir): else: print "unknown format: %d"%fmt return False - im = Image.fromstring('P', (w,h),pixeldata) + imp = Image.fromstring('P', (w,h),pixeldata) + imp.putpalette(palette) + # convert to RGBA + imrgb = imp.convert("RGBA") + # replace special colors + # 0 -> (0,0,0,0) = full transparency + # 1 -> (0,0,0,0x40) = shadow border + # 2 -> ??? + # 3 -> ??? + # 4 -> (0,0,0,0x80) = shadow body + # 5 -> (0,0,0,0) = selection highlight, treat as full transparency + # 6 -> (0,0,0,0x80) = shadow body below selection, treat as shadow body + # 7 -> (0,0,0,0x40) = shadow border below selection, treat as shadow border + pixrgb = np.array(imrgb) + pixp = np.array(imp) + pixrgb[pixp == 0] = (0,0,0,0) + pixrgb[pixp == 1] = (0,0,0,0x40) + pixrgb[pixp == 4] = (0,0,0,0x80) + pixrgb[pixp == 5] = (0,0,0,0) + pixrgb[pixp == 6] = (0,0,0,0x80) + pixrgb[pixp == 7] = (0,0,0,0x40) + imrgb = Image.fromarray(pixrgb) + im = Image.new('RGBA', (fw,fh), (0,0,0,0)) + im.paste(imrgb,(lm,tm)) else: # either width or height is zero - im = None - imo = Image.new('P', (fw,fh)) - imo.putpalette(palette) - if im: - imo.paste(im,(lm,tm)) - imo.save(outname) + im = Image.new('RGBA', (fw,fh), (0,0,0,0)) + im.save(outname) out_json["sequences"].append({"group":bid,"frames":frames}) with open(os.path.join(outdir,"%s.json"%bn),"w+") as o: json.dump(out_json,o,indent=4) diff --git a/definfo.py b/definfo.py index fa283f3..fb76e66 100644 --- a/definfo.py +++ b/definfo.py @@ -19,7 +19,12 @@ import struct from collections import defaultdict -from common import sanitize_filename +def sanitize_filename(fname): + # find the first character outside range [32-126] + for i,c in enumerate(fname): + if ord(c) < 32 or ord(c) > 126: + break + return fname[:i] def main(infile): f = open(infile) @@ -28,8 +33,8 @@ def main(infile): palette = [] for i in range(256): r,g,b = struct.unpack(">5)+1)<<5 rm = lm+w im = im.crop((lm,tm,rm,bm)) - if im.mode != 'P': - print "input images must have a palette" + if im.mode == 'P': + cursig =(fw,fh,im.getpalette()) + elif im.mode == 'RGBA': + cursig =(fw,fh,None) + else: + print "input images must be rgba or palette based" return False - cursig =(fw,fh,im.getpalette()) if not sig: sig = cursig else: @@ -204,16 +212,76 @@ def makedef(infile, outdir): print sig print cursig return False - data,size = fmtencoders[fmt](im) - infiles[bid].append((w,h,lm,tm,data,size)) + infiles[bid].append((lm,tm,im)) if len(infiles) == 0: print "no input files detected" return False fw,fh,pal = cursig - outname = os.path.join(outdir,p)+".def" - print "writing to %s"%outname + numframes = sum(len(l) for l in infiles.values()) + + # input images were RGB, find a good common palette + if not pal: + # create a concatenation of all images to create a good common palette + concatim = Image.new("RGB",(fw,fh*numframes)) + num = 0 + for _,l in infiles.items(): + for _,_,im in l: + concatim.paste(im, (0,fh*num)) + num+=1 + # convert that concatenation to a palette image to obtain a good common palette + concatim = concatim.convert("P", dither=None, colors=248, palette=Image.ADAPTIVE) + # concatenate the 248 colors to the 8 special ones + pal = [0x00, 0xff, 0xff, # full transparency + 0xff, 0x96, 0xff, # shadow border + 0xff, 0x64, 0xff, # ??? + 0xff, 0x32, 0xff, # ??? + 0xff, 0x00, 0xff, # shadow body + 0xff, 0xff, 0x00, # selection highlight + 0xb4, 0x00, 0xff, # shadow body below selection + 0x00, 0xff, 0x00, # shadow border below selection + ] + concatim.getpalette()[:744] + # convert RGBA images to P images with the common palette + for bid,l in infiles.items(): + newl = [] + for lm,tm,im in l: + w,h = im.size + if w == 0 or h == 0: + imp = None + else: + # must convert to RGB first for quantize() to work + imrgb = im.convert("RGB") + imp = imrgb.quantize(palette=concatim) + # now shift the colors by 8 + pix = np.array(imp) + pix += 8 + imp = Image.fromarray(pix) + # now replace full transparency in the original RGBA image with index 0 + pixrgba = np.array(im) + alpha = pixrgba[:,:,3] + pix[alpha == 0] = 0 + # now replace any half-transpareny with shadow body (index 4) + pix[(alpha > 0) & (alpha < 0xff)] = 4 + # TODO: calculate shadow border + # now put the palette with the special colors + imp.putpalette(pal) + newl.append((lm,tm,imp)) + infiles[bid] = newl + + # encode all images according to the required format + for bid,l in infiles.items(): + newl = [] + for lm,tm,im in l: + if im: + w,h = im.size + data,size = fmtencoders[fmt](im) + else: + w,h = 0,0 + data,size = '',0 + newl.append((w,h,lm,tm,data,size)) + infiles[bid] = newl + outf = open(outname, "w+") # write the header