gioconda.py

Created by fizban

Created on October 27, 2024

14.6 KB

Image of the Gioconda using a special compression algorithm based on lz77 and encoded in base64. Still, it is displayed zoomed from an image of 165x111 pixels


from kandinsky import fill_rect as fr, draw_string as ds, set_pixel
from ion import keydown as kd
from numpy import array as ar, concatenate as ct, zeros as zs

B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
ID = 1

class TP:
    def __init__(self, w1, w2, w3, mb, lo, ll):
        self.w1, self.w2, self.w3, self.mb = w1, w2, w3, mb
        self.lo, self.ll = lo, ll

        self.m1l = self._cmv(w1)
        self.m1d = self._cmv(6 - w1 if mb > 1 else 7 - w1)
        if mb == 1: self.md = self.m1d; return

        self.m2l = self._cmv(w2)
        self.m2d = self._cmv(13 - w2 if mb > 2 else 14 - w2)
        if mb == 2: self.md = self.m2d; return

        self.m3l = self._cmv(w3)
        self.m3d = self._cmv(20 - w3 if mb > 3 else 21 - w3)
        self.md = min(self.m3d, 2047)

    def _cmv(self, w): return (2 << (w - 1)) - 1 if w > 0 else 0

class SW:
    def __init__(self, ws):
        self.ws = ws
        self.buf = zs(ws, dtype=ID)
        self.idx = 0
        self.of = 0

    def add_b(self, b):
        self.buf[self.idx] = b
        self.of += ((self.idx + 1) // self.ws) * (self.ws)
        self.idx = (self.idx + 1) % self.ws

    def get_b(self, d):
        idx = (self.idx - d - 1) % self.ws
        return int(self.buf[idx])
    
    def get_l(self):
        return self.idx + self.of

def pw(gen):
    while True:
        try:
            a = next(gen)
            b = next(gen)
            yield a, b
        except StopIteration:
            break

class TI:
    def __init__(self, data, tps, p=None):
        self.img = dc(fb64(data), tps)
        self.tps = tps
        p = p or self.img
        self.clrs = [
            r565(next(p) * 256 + next(p))
            for _ in range(next(p) + 1)
        ]
        dims = (next(self.img) << 24) | (next(self.img) << 16) | (next(self.img) << 8) | next(self.img)
        self.w, self.h = dims >> 18, (dims >> 4) & 0x3FFF


    def dr_img(self, x, y):
        y0 = y
        for c in self.img:
            if y+2   > y0 + self.h*2:
                x, y = x +2, y0
            if self.clrs[c] != (255, 255, 255):
                fr(x,y,  2, 2, self.clrs[c])
            y += 2

def dld(eb, tps):
    if eb[0] & 0b11000000 == 0b10000000 or tps.mb == 1:
        d = (eb[0] >> tps.w1) & ((1 << (6 - tps.w1)) - 1)
        l = eb[0] & ((1 << tps.w1) - 1)
        return l + 3, d + 1, 1
    elif (eb[0] & 0b11000000 == 0b11000000 and eb[1] & 0b10000000 == 0) or tps.mb == 2:
        cv = ((eb[0] & 0b00111111) << (8 if tps.mb <= 2 else 7)) | eb[1]
        d = cv >> tps.w2
        l = cv & ((1 << tps.w2) - 1)
        if d <= tps.m1d: l += tps.m1l
        return l + 3, d + 1, 2
    elif (eb[0] & 0b11000000 == 0b11000000 and eb[1] & 0b10000000 == 0b10000000 and eb[2] & 0b10000000 == 0) or tps.mb == 3:
        cv = ((eb[0] & 0b00111111) << (15 if tps.mb <= 3 else 14)) | ((eb[1] & 0b01111111) << 8) | eb[2]
        d = cv >> tps.w3
        l = cv & ((1 << tps.w3) - 1)
        if d <= tps.m1d: l += tps.m1l + tps.m2l
        elif d <= tps.m2d: l += tps.m2l
        return l + 3, d + 1, 3
    elif (eb[0] & 0b11000000 == 0b11000000 and eb[1] & 0b10000000 == 0b10000000 and eb[2] & 0b10000000 == 0b10000000) or tps.mb == 4:
        cv = ((eb[0] & 0b00111111) << 22) | ((eb[1] & 0b01111111) << 15) | ((eb[2] & 0b01111111) << 8) | eb[3]
        d = cv >> 17
        l = cv & ((1 << 17) - 1)
        return l + 3, d + 1, 4

def dc(data, tps):
    tl, of, tx, p = len(data), 0, SW(tps.md), 0
    while of < tl:
        od = data[of]
        if od & 0x80 == 0x00:
            if tps.lo <= od <= tps.lo + 127 - tps.ll:
                tx.add_b(od)
                of += 1
            else:
                ll = 127 - od + 1 + tps.lo
                of += 1
                for i in range(ll):
                    tx.add_b(data[of + i])
                of += ll
        else:
            l, d, nb = dld(data[of:of + 4], tps)
            of += nb
            ep = tx.get_l() - (d - l)
            if ep <= tx.get_l():
                for i in range(l):
                    tx.add_b(tx.get_b(d - 1))
            else:
                ch = [tx.get_b(d - i - 1) for i in range(d)] * (l // d + 1)
                for i in range(l):
                    tx.add_b(ch[i])
        while p < tx.get_l():
            yield tx.get_b(tx.get_l() - p - 1)
            p += 1

def r565(c): return ((c >> 11 & 0x1F) * 255 // 31, (c >> 5 & 0x3F) * 255 // 63, (c & 0x1F) * 255 // 31)

def gclr(p):
    p = fb64(p)
    return [r565(p[1 + i] * 256 + p[2 + i]) for i in range(0, p[0] * 2, 2)]

def fb64(eb):
    dl = (len(eb) * 3) // 4 - eb.count('=')
    da = zs(dl, dtype=ID)
    ai = 0
    for i in range(0, len(eb), 4):
        bl = eb[i:i+4].replace("=", "A")
        bi = sum((B64.index(c) << (6 * (3 - j))) for j, c in enumerate(bl))
        for byte in bi.to_bytes(3, "big"):
            if ai < dl:
                da[ai] = byte
                ai += 1
    return da

tps = TP(2, 3, 9, 3, 0, 64)

img = TI('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'
                    , tps)

img.dr_img(0,0)

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.