rabbit_full2.py

Created by fizban

Created on October 30, 2024

19.8 KB

Image of a bunny. The image has been encoded in base64 in a special 16 color compressed format on top of an lz77 based compression algorithm


from kandinsky import fill_rect as fr
from numpy import  zeros as zs

_ID = const(1)


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

        self.m1l = self._cmv(w1)
        self.m1d = self._cmv(6 - w1 if w2 > 0 else 7 - w1)
        if w2 == 0: return

        self.m2l = self._cmv(w2)
        self.m2d = self._cmv(13 - w2 if w3 > 0 else 14 - w2)


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



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

    def add_b(self, bytes):
      for b in bytes:
        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):
        return int(self.buf[(self.idx - d - 1) % self.ws])


class TI:
    def __init__(self, p=None):
        self.img = dc(fb64(data))
        self.z = 2
        self.dr_img = self.dr_imgy
        self.gcl = self.gclp
        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 gclp(self):
        clrs = self.clrs  
        yield from ((clrs[c], 1) for c in self.img)
    
    def dr_ln(self, x, y, lx, ly, c):
        if c != (255, 255, 255):
            fr(x, y, lx, ly, c)

    def dr_imgy(self, x, y):
        y0, pc, tl, z  = y, -1, 0, self.z
        for c, l in self.gcl():
            sh = l * z
            if y + sh > y0 + self.h * z:
                if tl > 0:
                    self.dr_ln(x, y - tl, z, tl, pc)
                x, y, pc, tl = x + z, y0, c, 0
            if pc != c:
                if pc != -1 and tl > 0:
                    self.dr_ln(x, y - tl, z, tl, pc)
                pc, tl = c, sh
            else:
                tl += sh
            y += sh
        self.dr_ln(x, y - tl, z, tl, pc)

    def dr_img_x(self, x, y):
        x0, pc, tl, z = x, -1, 0, self.z
        for c, l, z in self.gcl():
            sw = l * z
            if x + sw > x0 + self.w * z:
                if tl > 0:
                    self.dr_ln(x - tl, y, tl, z, pc)
                y, x, pc, tl = y + z, x0, c, 0

            if pc != c:
                if pc != -1 and tl > 0:
                    self.dr_ln(x - tl, y, tl, z, pc)
                pc, tl = c, sw
            else:
                tl += sw

            x += sw

        self.dr_ln(x - tl, y, z, tl, pc)


def dld(od, eb):
    if od & 0xC0 == 0x80 or tps.w2 == 0:
        d = (od >> tps.w1) & ((1 << (6 - tps.w1)) - 1)
        l = od & ((1 << tps.w1) - 1)
        return l + 3, d + 1, 1
    eb1 = next(eb)
    if (od & 0xC0 == 0xC0 and eb1 & 0x80 == 0) or tps.w3 == 0:
        cv = ((od & 0x3F) << (8 if tps.w3 == 0 else 7)) | eb1
        d = cv >> tps.w2
        l = cv & ((1 << tps.w2) - 1)
        if d <= tps.m1d: l += tps.m1l
        return l + 3, d + 1, 2
    eb2 = next(eb)
    if (od & 0xC0 == 0xC0 and eb1 & 0x80 == 0x80 and eb2 & 0x80 == 0):
        cv = ((od & 0x3F) <<  15) | ((eb1 & 0x7F) << 8) | eb2
        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
    eb3 = next(eb)


def dc(data):
    of, tx, p =  0, SW(2047), 0
    for od in data:
        if od & 0x80 == 0x00:
            if 0 <= od <= 127 - tps.ll:
                tx.add_b([od])
                of += 1
            else:
                ll = 127 - od + 1 
                of += 1 + ll
                tx.add_b(next(data) for _ in range(ll))
        else:
            l, d, nb = dld(od, data)
            of += nb
            tx_l = tx.idx + tx.of
            ep = tx_l - (d - l)
            if ep <= tx_l:
                tx.add_b(tx.get_b(d - 1) for _ in range(l))
            else:
                ch = [tx.get_b(d - i - 1) for i in range(d)] * (l // d + 1)
                tx.add_b(ch[:l])
        tx_l = tx.idx + tx.of
        while p < tx_l:
            yield tx.get_b(tx_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):
    base64_index = zs(128, dtype=_ID)
    for i, ch in enumerate(b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"): base64_index[ch] = i
    dl, ai = (len(eb) * 3) // 4 - eb.count(b'='), 0
    for i in range(0, len(eb), 4):
        bi = (base64_index[eb[i]] << 18) | (base64_index[eb[i+1]] << 12) | (base64_index[eb[i+2]] << 6) | base64_index[eb[i+3]]
        for byte in (bi >> 16, (bi >> 8) & 0xFF, bi & 0xFF):
            if ai < dl: yield byte; ai += 1


tps = TP(2, 3, 9, 64)
data = b'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'

img = TI()
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.