From d4a6091f6fb0fb6568062d7de1b9da103e2f07d1 Mon Sep 17 00:00:00 2001 From: hkc Date: Thu, 4 Jul 2024 20:37:47 +0300 Subject: [PATCH] Added animation support and blobs --- async-bot.py | 79 ++++++++++++++++++++++++++++++++----------- pictures/bit.txt | 1 + pictures/loading.gif | Bin 0 -> 15196 bytes pictures/neko.gif | Bin 0 -> 452 bytes pictures/neko.png | Bin 7079 -> 6478 bytes settings.json | 20 +++++++++-- 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 pictures/bit.txt create mode 100644 pictures/loading.gif create mode 100644 pictures/neko.gif diff --git a/async-bot.py b/async-bot.py index 21e8e49..47ed7c1 100644 --- a/async-bot.py +++ b/async-bot.py @@ -1,12 +1,17 @@ import asyncio -from typing import Optional +from typing import NewType, Optional from socketio import AsyncSimpleClient from aiohttp import ClientSession from aiohttp_socks import ProxyConnector -from PIL import Image, ImageFont, ImageDraw, ImageFilter +from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageSequence from base64 import b64decode from random import choice from json import load +from time import time as time_now + + +PixelMap = NewType("PixelMap", dict[int, bool]) +Animation = NewType("Animation", tuple[list[PixelMap], float]) class AsyncBotManager: @@ -16,11 +21,13 @@ class AsyncBotManager: self.canvas = Image.new("1", (1000, 1000)) self.font = ImageFont.load_default(8) - self.difference: dict[int, bool] = {} + self.difference: PixelMap = PixelMap({}) self._last_update = 0 self._shutdown: bool = False self.avoid: set[int] = set() + self.animations: list[Animation] = [] + def put_text(self, x: int, y: int, text: str): with Image.new("LA", (int(self.font.getlength(text) + 12), 16)) as im: draw = ImageDraw.Draw(im) @@ -43,18 +50,34 @@ class AsyncBotManager: self.put_index(x + y * 1000, val) def put_index(self, index: int, value: bool): - if not index in self.avoid: + if index not in self.avoid: self.difference[index] = value - def add_avoid_rect(self, sx: int, sy: int, w: int, h: int): + def add_animation( + self, ox: int, oy: int, image: Image.Image, spf: float = 1 + ) -> None: + animation = Animation(([], spf)) + for frame in ImageSequence.Iterator(image): + frame_la = frame.convert("LA") + pixelmap = PixelMap({}) + for y in range(frame_la.height): + for x in range(frame_la.width): + l, a = frame_la.getpixel((x, y)) # type: ignore + index = x + ox + (y + oy) * 1000 + if a > 128 and index not in self.avoid: + pixelmap[index] = l > 128 + animation[0].append(pixelmap) + self.animations.append(animation) + + def add_avoid_rect(self, sx: int, sy: int, w: int, h: int) -> None: for y in range(sy, sy + h): ox = y * 1000 self.add_avoid_range(sx + ox, sx + w + ox) - def add_avoid_range(self, start: int, stop: int, step: int = 1): + def add_avoid_range(self, start: int, stop: int, step: int = 1) -> None: self.avoid |= set(range(start, stop, step)) - def add_avoid_index(self, *indices: int): + def add_avoid_index(self, *indices: int) -> None: self.avoid |= set(indices) def get_difference_image(self) -> Image.Image: @@ -71,13 +94,13 @@ class AsyncBotManager: im.putpixel((x, y), (255, 0, 0)) return im.copy() - async def listener(self): + async def listener(self) -> None: async with ClientSession() as http: async with http.get(f"{self.base}/api/initial-state") as req: data = await req.json() buffer = b64decode(data["full_state"].encode() + b"=") self.canvas.paste(Image.frombytes("1", (1000, 1000), buffer)) - self._last_update: int = data["timestamp"] + self._last_update = data["timestamp"] async with AsyncSimpleClient(http_session=http) as sio: await sio.connect(f"{self.base}/socket.io") while not self._shutdown: @@ -87,12 +110,12 @@ class AsyncBotManager: image = Image.frombytes("1", (1000, 1000), buffer) self.canvas.paste(image) image.close() - self._last_update: int = data["timestamp"] + self._last_update = data["timestamp"] elif event == "batched_bit_toggles": bits_on, bits_off, timestamp = data if timestamp < self._last_update: print("SKIPPING UPDATES: TOO OLD") - self._last_update: int = timestamp + self._last_update = timestamp for ndx in bits_on: y, x = divmod(ndx, 1000) self.canvas.putpixel((x, y), 255) @@ -101,6 +124,11 @@ class AsyncBotManager: self.canvas.putpixel((x, y), 0) else: print("unknown event", event, data) + for pixmaps, spf in self.animations: + frame_index = int(time_now() / spf) + self.difference.update( + pixmaps[frame_index % len(pixmaps)] + ) async def writer( self, @@ -133,13 +161,8 @@ class AsyncBotManager: self._shutdown = True await self._listener_task - def copy(self): - copy = self.__class__(self.base) - copy.difference = dict.copy(self.difference) - return copy - -async def amain(): +async def amain() -> None: with open("settings.json", "r") as fp: settings = load(fp) @@ -168,6 +191,9 @@ async def amain(): elif elem["type"] == "image": with Image.open(elem["path"]).convert("LA") as im: mgr.put_image(elem["x"], elem["y"], im) + elif elem["type"] == "animation": + with Image.open(elem["path"]) as anim: + mgr.add_animation(elem["x"], elem["y"], anim, elem["spf"]) elif elem["type"] == "rgb111": ox, oy = elem["x"], elem["y"] with Image.open(elem["path"]).convert("RGBA") as im: @@ -189,8 +215,8 @@ async def amain(): r, g, b, a = im.getpixel((x, y)) # type: ignore if a < 128: continue - ndx_start: int = (x + ox + (y + oy) * 250) * 16 - color = (r >> 3) << 13 + ndx_start = (x + ox + (y + oy) * 250) * 16 + color: int = (r >> 3) << 13 color |= (g >> 2) << 5 color |= b >> 3 @@ -202,6 +228,21 @@ async def amain(): for y in range(elem["y"], elem["y"] + elem["h"]): for x in range(elem["x"], elem["x"] + elem["w"]): mgr.put_pixel(x, y, elem["fill"]) + elif elem["type"] == "blob": + with open(elem["path"], "rb") as fp: + offset = elem["offset"] + length = elem.get("length", 1000000) + written = 0 + while (char := fp.read(1)): + byte = char[0] + if written > length: + break + for i in range(8): + if written > length: + break + mgr.put_index(offset, bool((byte >> (7 - i)) & 1)) + written += 1 + offset += 1 mgr.get_difference_image().save("result.png") mgr.get_avoid_image().save("avoid.png") diff --git a/pictures/bit.txt b/pictures/bit.txt new file mode 100644 index 0000000..dbbe0a6 --- /dev/null +++ b/pictures/bit.txt @@ -0,0 +1 @@ +The bit is the most basic unit of information in computing and digital communication. The name is a portmanteau of binary digit. The bit represents a logical state with one of two possible values. These values are most commonly represented as either "1" or "0", but other representations such as true/false, yes/no, on/off, or +/− are also widely used. The relation between these values and the physical states of the underlying storage or device is a matter of convention, and different assignments may be used even within the same device or program. It may be physically implemented with a two-state device. A contiguous group of binary digits is commonly called a bit string, a bit vector, or a single-dimensional (or multi-dimensional) bit array. A group of eight bits is called one byte, but historically the size of the byte is not strictly defined. Frequently, half, full, double and quadruple words consist of a number of bytes which is a low power of two. A string of four bits is usually a nibble. In information theory, one bit is the information entropy of a random binary variable that is 0 or 1 with equal probability, or the information that is gained when the value of such a variable becomes known. As a unit of information, the bit is also known as a shannon, named after Claude E. Shannon. The symbol for the binary digit is either "bit", per the IEC 80000-13:2008 standard, or the lowercase character "b", per the IEEE 1541-2002 standard. Use of the latter may create confusion with the capital "B" which is the international standard symbol for the byte. diff --git a/pictures/loading.gif b/pictures/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..25f060cbf191137bf89cdb64c4a2b8cb7304aaf0 GIT binary patch literal 15196 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 XpQI`oxl`WyNv2=D;`~3uRQ10Al^-%C literal 0 HcmV?d00001 diff --git a/pictures/neko.gif b/pictures/neko.gif new file mode 100644 index 0000000000000000000000000000000000000000..983001f9489dcec30c58007d7b4adb5206423f77 GIT binary patch literal 452 zcmZ?wbhEHbRA5kGc+AA`|NnmmhQAC%1I7Q`ey$o>o)$E-`==n#l!`c(_YOi z%aA_2rsLlFx12TotIZkDU4HeUWBxpYBcA)_SU>WpWYJ}GN)(ehX3b;PdTq`kYJ zzN$I8>u`$qtvNZnx6asJXL0`ZTj$WC>V_EiqOw+%$h;1X*aq(&2GQ!0^nmgT;c0U_ z%cqFUT^u`Own1x1M(FYtA^mpw?ag7UCao&0t1)+V6~yM+*~qSCbjsvvSkWjqYnAq^ zL&`6G-|%iXt6O9p&1Vukv2LBekwwnj5|e8SB_EksyG)omEB0E1=e!SFC#N2Lvi|jQ z9Y@2rdJ!`U``#8S*hoIx^)R{CGTT)oqr5q{s;#yqFDb3tt}}f?NzarRv-%mu?loSs mGlQEtT#V90+q*m}CPl1GP@AwmV);go*3wzdCi~b08LR;go~oz- literal 0 HcmV?d00001 diff --git a/pictures/neko.png b/pictures/neko.png index fe91d4f50d0f66fb68c34a9b6856129da820d6d6..0dd3b423e7b623a2b5cb1a6433a99ac1fe0f5dc1 100644 GIT binary patch delta 1793 zcmZ2(e$HruG84zSiK@HUEv-xptqd(EKC5MFW#632Sj|-b{g=j~2Cf0a^#f@+(C&H+ zpRaGwV1EBg`vDg!_4^;0p#(AS2U8b{2{2pgVb-9?;tCYFS-9PXWD%4J^a^gn>oI)= z)dr#L7#8jO&#<%1p%kheo zdI}mK2rmNTAH^?-z(ug&{sAe)Vh2zdO)=C~kmw7zhrm1}%fMk-kJZa)u7>&?VmHtP zgfEcNAvBO7;R&-Dnrg5+8sx8fn4z%9L(t$4eky23t4(16| zS{0F4Q6<3Q_Wy4(JiFdww7HP`HnWO>ak6QOfu)gdqJ_DEu1T_Kl5S#Ja++?MS&Ff- zQL2ThrFrV)0)BaAi!_TABU2M&U1N(BLtPUCLla$#G$1R*!rU~`(8xF`C2{g5ehn1^ zqcn5#q(pOFi)5n|T@!N)Q(a3-0~1|y3v+YJ#N-sSBumrD|M=s$3=NGe49v|;jZG(~ z2^7GJ@yT}u)ZuJy!7depB+JwkW6Km>BV$9Ly(Y$Hx`|1thPtMfNofY=7KSEfCdrd` z3I;+n85wLA6w2dZ=~MhCHn~~KlU+bl#M64hyUCZOH0rl_x;Tbd_`eNqR}C$BPO+tKMz*Qe{}~65`<}&$@xr>y#X~!rg6hY+Fjj9#0Gu&%Cf}ZC&y?j|J;C o_pdV2yS{X7{8=lFJ+(i+>br0<^ZF&Psb>HJPgg&ebxsLQ0NTgN8vp;Ul<8Oy2NUI?@^HM$ig;I`z56bp&N-I-w-(flU%@+h=zXf&_lQg2$TC*tDKw+&z3;+e9^nHkx|A&NgJ<(uKq)y?#BpxYE&4?iX#YeIJ5Z zwqJuP(A49?xyyC>g1)*aeQu8X{iL{BQeuueF_LS`lye7Nb$YkCc3`Kotywr!9K7oyxGVRij7@9o9J<@{tbPb>?{!uHeGNcgYDyznS#eBV zmLD3?V^~bcl`;K$fB3stKdmbWw6S=m%FA<2|DiF?FAQ>wj9I`mR@c(H__*OpM@rzY z1LmmDM+$r!xm?oi_k7*oM-~JQhayuIK_OFxXni}2XR$w|ed*QCYB|5K#ZuD#vkSgV zrcnRYka;H+axUr3Q^+}J$^qsCCcY&eJ)qDVa4gbt&P9{HmqPLWdfJW7w7iO9aARx4 z#jk1FK|^Bjr>Jzu-P_JWlM|FO;ZJrt&s0UBlkBXmG@@VrCdHxIU%0T-0BpeTWsYLm z^CO1)VJeh-ymmmZPbe%*N)7F@{x;OMmJVpL2QALX4uXt94q`GF6I=@UfP|;5!K^~# z%POD+wV1MlNUs|pN&0i6h7M@?aVQU5Vg#4i<60j(Hy`TRu-OI@|FcOHSY7T>R zzW@?I6O%6kXkHo63^D!t&KMKJnhl=rV63c_w13{W{niW44`LN3v8n?tG4fxG*Uk<(uw964Ewi?8zC(c^$wnvjIFfP4`qewu+T7XwCM-wRNy#_{{ z4cd>K<42)jkg?5O(sgAQ6kXNc`LuNCj2cVUgD}?)XnLaG920Pct}nrNSLV}#V%vtt zQA{X9C#YW*fMRJBlWf3>0MM`jUQK?36cconLyrx3e>H)VZnQXSY*t=JTeIN=;KD}Y z$>N;8q)2n%qtN>%TB%-VQOT1_0kj?Uz#U;p2UYD4pPRsG^h=n)Xo&cONjstnf$a2p z{3NV=nqT}`0u!3x8hnH9V^?a*P3Yq$^`_l;@F}fsVQPN66YITJj;Hud_i=5ovB z0X>QCFt{Fw(Jdoak7SOQ7JE5=!8i%DBE*C;z!YaK1EM7C@O(owP-yHJh>BNT>`;!= z$Q|qsC*1}Hc!YFwVKdkzxvA8s0X{r5A7$~RJ*Q8*&Kzh3k?hejxGA4GdFto6Q*L5Y zx0f4S9{f^gsoetNig#sPMmnj99SRhqlI39vyN|i{0OLZCfL7V0Om7*|o;avv|a@ z@KwvBWl{a>mit!Eo!-z#5&qV6zT}6|8?PUZFi2h;-fja=dvoN Y*%eym{-MOJ4g{ZYdE}~ZS8U1n6J!}Om;e9( diff --git a/settings.json b/settings.json index e0b8343..c96b4e7 100644 --- a/settings.json +++ b/settings.json @@ -50,6 +50,12 @@ } ], "elements": [ + { + "type": "blob", + "path": "./pictures/bit.txt", + "offset": 16384, + "length": 12632 + }, { "type": "image", "path": "./pictures/kangel.png", @@ -69,16 +75,24 @@ "y": 333 }, { - "type": "image", - "path": "./pictures/neko.png", + "type": "animation", + "path": "./pictures/neko.gif", "x": 263, - "y": 229 + "y": 225, + "spf": 5 }, { "type": "image", "path": "./pictures/casey.png", "x": 256, "y": 256 + }, + { + "type": "animation", + "path": "./pictures/loading.gif", + "x": 436, + "y": 436, + "spf": 10 } ] }