#!/usr/bin/env python3
"""Misst die Bedienleiste aus einem XWD-Bild -- FARBTON UND HELLIGKEIT.

Warum beide: bei OrientOS liess ein reiner Helligkeitstest eine
Vertauschung von Rot und Blau durch. RGB(59,41,30) und RGB(30,41,59)
haben exakt dieselbe Helligkeit und sind zwei verschiedene Farben.
Deshalb wird JEDER KANAL EINZELN gegen den Sollwert gehalten, und der
Fall "gedreht" wird ausdruecklich benannt.
"""
import struct, sys, collections

def xwd_lesen(pfad):
    d = open(pfad,'rb').read()
    # XWDFileHeader, 25 Felder, alle big-endian -- die Reihenfolge ist
    # die aus X11/XWDFile.h. Die Masken stehen an Feld 15/16/17
    # (visualclass davor), NICHT bei Oktett 56: das war der Fehler im
    # ersten Anlauf, und er machte jeden Blaukanal zu 0.
    f = struct.unpack('>25I', d[:100])
    hsize, depth, w, h = f[0], f[3], f[4], f[5]
    byteorder, bpp, bpl = f[7], f[11], f[12]
    rmask, gmask, bmask = f[14], f[15], f[16]
    ncolors = f[18]
    off = hsize + ncolors*12
    return w, h, bpp, bpl, off, d, rmask, gmask, bmask, byteorder

def shift_of(m):
    s = 0
    while m and not (m & 1):
        m >>= 1; s += 1
    return s

def leser(pfad):
    w,h,bpp,bpl,off,d,rm,gm,bm,bo = xwd_lesen(pfad)
    rs, gs, bs = shift_of(rm), shift_of(gm), shift_of(bm)
    nb = bpp//8
    # byteorder 0 = LSBFirst. Das Feld gilt fuer die BILDPUNKTE, waehrend
    # der Kopf immer big-endian ist.
    end = 'big' if bo else 'little'
    def px(x,y):
        o = off + y*bpl + x*nb
        v = int.from_bytes(d[o:o+nb], end)
        return ((v&rm)>>rs, (v&gm)>>gs, (v&bm)>>bs)
    return w,h,px

if __name__ == '__main__':
    pfad = sys.argv[1]; soll = sys.argv[2] if len(sys.argv)>2 else None
    CH = int(sys.argv[3]) if len(sys.argv)>3 else 44
    w,h,px = leser(pfad)
    print("BILD %dx%d  %s" % (w,h,pfad.split('/')[-1]))
    z = collections.Counter()
    for y in range(0,min(CH,h)):
        for x in range(0,w,2):
            z[px(x,y)] += 1
    ges = sum(z.values())
    print("  Leiste y=0..%d, haeufigste Farben:" % CH)
    for (r,g,b),n in z.most_common(6):
        print("    RGB(%3d,%3d,%3d) = #%02x%02x%02x  %5.1f%%  Hell %5.1f"
              % (r,g,b,r,g,b,100.0*n/ges, 0.2126*r+0.7152*g+0.0722*b))
    if soll:
        sr,sg,sb = int(soll[0:2],16),int(soll[2:4],16),int(soll[4:6],16)
        top = z.most_common(1)[0][0]
        d1 = (abs(top[0]-sr),abs(top[1]-sg),abs(top[2]-sb))
        d2 = (abs(top[0]-sb),abs(top[1]-sg),abs(top[2]-sr))
        print("  SOLL #%s = RGB(%d,%d,%d)" % (soll,sr,sg,sb))
        print("  IST  RGB(%d,%d,%d)  Abweichung je Kanal (%d,%d,%d)"
              % (top[0],top[1],top[2],d1[0],d1[1],d1[2]))
        if sum(d1)==0: print("  URTEIL: EXAKT")
        elif sum(d2)==0 and sr!=sb: print("  URTEIL: ROT UND BLAU VERTAUSCHT !!!")
        elif sum(d1)<=3: print("  URTEIL: gleich (Rundung)")
        else: print("  URTEIL: ABWEICHUNG")
