From f216fa3502b34acf8dd734eca96c08b85135f217 Mon Sep 17 00:00:00 2001 From: acidvegas Date: Thu, 29 Jun 2023 21:18:56 -0400 Subject: [PATCH] Updated img2irc to use OpenCV instead of Pillow, random functions use a better seed for better randomization output, .ascii img moved into play function, etc --- README.md | 31 ++++--- __pycache__/img2irc.cpython-39.pyc | Bin 0 -> 6570 bytes img2irc.py | 125 ++++++++++++++--------------- scroll.py | 114 +++++++++++++------------- 4 files changed, 135 insertions(+), 135 deletions(-) create mode 100644 __pycache__/img2irc.cpython-39.pyc diff --git a/README.md b/README.md index 78eca9e..3451b6c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Designed to be portable, there is no API key needed, no local art files needed, ## Dependencies * [python](https://www.python.org/) * [chardet](https://pypi.org/project/chardet/) *(`pip install chardet`)* -* [pillow](https://pypi.org/project/pillow/) *(`pip install pillow`)* +* [numpy](https://pypi.org/project/numpy/) *(`pip install numpy`)* +* [opencv-python](https://pypi.org/project/opencv-python/) *(`pip install opencv-python`)* ## Commands | Command | Description | @@ -32,21 +33,17 @@ Designed to be portable, there is no API key needed, no local art files needed, **NOTE**: The sync & settings commands are admin only! `admin` is a *nick!user@host* mask defined in [scroll.py](https://github.com/ircart/scroll/blob/master/scroll.py) ## Settings -| Setting | Type | Description | -| ---------------- | ------------ | -------------------------------------------------------------------------------------------- | -| `flood` | int or float | delay between each command | -| `ignore` | str | directories to ignore in `.ascii random` *(comma seperated list, no spaces)* | -| `lines` | int | max lines outside of #scroll | -| `msg` | int or float | delay between each message sent | -| `paste` | boolean | enable or disable `.ascii play` | -| `png_brightness` | int or float | increase or decrease brightness for `.ascii img` output | -| `png_contrast` | int or float | increase or decrease contrast for `.ascii img` output | -| `png_effect` | str | change the effect for `.ascii img` output *(blackwhite, blue, greyscale, invert, or smooth)* | -| `png_palette` | str | palette option for `.ascii img` output *(RGB99 or RGB88)* | -| `png_width` | int | maximum width for `.ascii img` output | -| `results` | int | max results to return in `.ascii search` | - -**NOTE**: Setting **0** to `png_brightness`, `png_contrast`, or `png_effect` will disable the setting. +| Setting | Type | Description | +| --------------------- | ------------ | -------------------------------------------------------------------------------------------- | +| `flood` | int or float | delay between each command | +| `ignore` | str | directories to ignore in `.ascii random` *(comma seperated list, no spaces)* | +| `lines` | int | max lines outside of #scroll | +| `msg` | int or float | delay between each message sent | +| `paste` | boolean | enable or disable `.ascii play` | +| `png_quantize_colors` | int | quantize color option for `.ascii img` output | +| `png_palette` | str | palette option for `.ascii img` output *(RGB99 or RGB88)* | +| `png_width` | int | maximum width for `.ascii img` output | +| `results` | int | max results to return in `.ascii search` | ## Preview @@ -59,7 +56,7 @@ Come pump with us in **#scroll** on [irc.supernets.org](ircs://irc.supernets.org ## Todo - git integration to `git clone` the [ircart](https://github.com/ircart/ircart) repository & `git pull` on `.ascii sync` *(Load art files into RAM for faster pumping)* - `.ascii scroll` command to loop playing random art files *(Stopped with `.ascii stop`)* -- Add arguments to `.ascii img` for contrast, brightness, * effects *(Take them out of self.settings)* +- Add arguments to `.ascii img` for palette, width, & other options - Setting to auto convert any image link to IRC art *(Emulate link previews like on Discord LOL)* - `.ascii record` to record lines from the senders nick for uploads *(Stopped with `.ascii stop`)* - Improve randomness with `.ascii random` diff --git a/__pycache__/img2irc.cpython-39.pyc b/__pycache__/img2irc.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18190c2b5f60dd4912c3abdb736c44db3d34f9a4 GIT binary patch literal 6570 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 literal 0 HcmV?d00001 diff --git a/img2irc.py b/img2irc.py index cfaf6a1..8491110 100644 --- a/img2irc.py +++ b/img2irc.py @@ -2,30 +2,25 @@ # Scroll IRC Art Bot - Developed by acidvegas in Python (https://git.acid.vegas/scroll) ''' -Pull Request: - - https://github.com/ircart/scroll/pull/3 - - Props: - - forked idea from malcom's img2irc (https://github.com/waveplate/img2irc) - - big props to wrk (wr34k) for forking this one - - brightness/contrast/effects & more added by acidvegas - -Interesting: - - https://pythonexamples.org/pillow-image-blend/ - - https://pythonexamples.org/pillow-access-rgb-channels-of-image/ +Props: + - forked idea from malcom's img2irc (https://github.com/waveplate/img2irc) + - big props to wrk (wr34k) for forking this + opencv implementation ''' -import io - try: - from PIL import Image, ImageEnhance, ImageFilter, ImageOps + import cv2 except ImportError: - raise SystemExit('missing required \'pillow\' library (https://pypi.org/project/pillow/)') + raise SystemExit('missing required \'opencv-python\' library (https://pypi.org/project/opencv-python/)') +try: + import numpy as np +except ImportError: + raise SystemExit('missing required \'numpy\' library (https://pypi.org/project/numpy/)') -effects = ('blackwhite', 'blur', 'greyscale', 'invert', 'smooth') palettes = { + 'RGB16': [0xffffff, 0x000000, 0x00007f, 0x009300, 0xff0000, 0x7f0000, 0x9c009c, 0xfc7f00, + 0xffff00, 0x00fc00, 0x009393, 0x00ffff, 0x0000fc, 0xff00ff, 0x0, 0x0], 'RGB88': [0xffffff, 0x000000, 0x00007f, 0x009300, 0xff0000, 0x7f0000, 0x9c009c, 0xfc7f00, - 0xffff00, 0x00fc00, 0x009393, 0x00ffff, 0x0000fc, 0xff00ff, 0x0, 0x0, + 0xffff00, 0x00fc00, 0x009393, 0x00ffff, 0x0000fc, 0xff00ff, 0x0, 0x0, 0x470000, 0x472100, 0x474700, 0x324700, 0x004700, 0x00472c, 0x004747, 0x002747, 0x000047, 0x2e0047, 0x470047, 0x47002a, 0x740000, 0x743a00, 0x747400, 0x517400, 0x007400, 0x007449, 0x007474, 0x004074, 0x000074, 0x4b0074, 0x740074, 0x740045, @@ -35,7 +30,6 @@ palettes = { 0xff5959, 0xffb459, 0xffff71, 0xcfff60, 0x6fff6f, 0x65ffc9, 0x6dffff, 0x59b4ff, 0x5959ff, 0xc459ff, 0xff66ff, 0xff59bc, 0xff9c9c, 0xffd39c, 0xffff9c, 0xe2ff9c, 0x9cff9c, 0x9cffdb, 0x9cffff, 0x9cd3ff, 0x9c9cff, 0xdc9cff, 0xff9cff, 0xff94d3], - 'RGB99': [0xffffff, 0x000000, 0x00007f, 0x009300, 0xff0000, 0x7f0000, 0x9c009c, 0xfc7f00, 0xffff00, 0x00fc00, 0x009393, 0x00ffff, 0x0000fc, 0xff00ff, 0x7f7f7f, 0xd2d2d2, 0x470000, 0x472100, 0x474700, 0x324700, 0x004700, 0x00472c, 0x004747, 0x002747, @@ -51,50 +45,31 @@ palettes = { 0xbcbcbc, 0xe2e2e2, 0xffffff] } -def convert(data, max_line_len, img_width=80, palette='RGB99', brightness=False, contrast=False, effect=None): +def convert(data, max_line_len, img_width=80, palette='RGB99', quantize_colors=None): if palette not in palettes: raise Exception('invalid palette option') - if effect and effect not in effects: - raise Exception('invalid effect option') palette = palettes[palette] - image = Image.open(io.BytesIO(data)) + np_arr = np.asarray(bytearray(data), dtype="uint8") + image = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) del data - if brightness: - image = ImageEnhance.Brightness(im).enhance(brightness) - if contrast: - image = ImageEnhance.Contrast(image).enhance(contrast) - if effect == 'blackwhite': - image = image.convert("1") - elif effect == 'blur': - image - image.filter(ImageFilter.BLUR) - elif effect == 'greyscale': - image = image.convert("L") - elif effect == 'invert': - image = ImageOps.invert(image) - elif effect == 'smooth': - image = image.filter(ImageFilter.SMOOTH_MORE) - return convert_image(image, max_line_len, img_width, palette) + return convert_image(image, quantize_colors, max_line_len, img_width, palette) -def convert_image(image, max_line_len, img_width, palette): - (width, height) = image.size - img_height = img_width / width * height - del height, width - image.thumbnail((img_width, img_height), Image.Resampling.LANCZOS) - del img_height +def convert_image(orig_image, quantize_colors, max_line_len, img_width, palette): + image = ircize(orig_image, img_width, quantize_colors) CHAR = '\u2580' buf = list() - for i in range(0, image.size[1], 2): - if i+1 >= image.size[1]: - bitmap = [[rgb_to_hex(image.getpixel((x, i))) for x in range(image.size[0])]] - bitmap += [[0 for _ in range(image.size[0])]] + for i in range(0, image.shape[0], 2): + if i+1 >= image.shape[0]: + bitmap = [[bgr_to_hex(image[i, x]) for x in range(image.shape[1])]] + bitmap += [[0 for _ in range(image.shape[1])]] else: - bitmap = [[rgb_to_hex(image.getpixel((x, y))) for x in range(image.size[0])] for y in [i, i+1]] + bitmap = [[bgr_to_hex(image[y, x]) for x in range(image.shape[1])] for y in [i, i+1]] top_row = [AnsiPixel(px, palette) for px in bitmap[0]] bottom_row = [AnsiPixel(px, palette) for px in bitmap[1]] buf += [""] last_fg = last_bg = -1 ansi_row = list() - for j in range(image.size[0]): + for j in range(image.shape[1]): top_pixel = top_row[j] bottom_pixel = bottom_row[j] pixel_pair = AnsiPixelPair(top_pixel, bottom_pixel) @@ -112,32 +87,56 @@ def convert_image(image, max_line_len, img_width, palette): last_fg = fg last_bg = bg if len(buf[-1].encode('utf-8', 'ignore')) > max_line_len: - if img_width - 5 < 10: - raise Exception('internal error') - return convert_image(image, max_line_len, img_width-5, palette) + if img_width - 5 < 5: + raise Exception('image would get too small') + return convert_image(orig_image, quantize_colors, max_line_len, img_width-5, palette) return buf +def ircize(image, img_width, quantize_colors): + (height, width, _) = image.shape + img_height = img_width / width * height + image = cv2.resize(image, (int(img_width), int(img_height)), interpolation=cv2.INTER_AREA) + brightness = np.sum(image) / (255 * image.shape[0] * image.shape[1]) + minimum_brightness = 0.72 + ratio = brightness / minimum_brightness + if ratio < 1: + image = cv2.convertScaleAbs(image, alpha = 1 / ratio, beta = 0) + imgf = np.float32(image).reshape(-1, 3) + criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,20,2.0) + compactness, label, center = cv2.kmeans(imgf, quantize_colors, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) + center = np.uint8(center) + final_img = center[label.flatten()] + image = final_img.reshape(image.shape) + return image + def hex_to_rgb(color): - r = color >> 16 - g = (color >> 8) % 256 - b = color % 256 + r = (color >> 16) & 255 + g = (color >> 8) & 255 + b = color & 255 return (r,g,b) def rgb_to_hex(rgb): - r = rgb[0] - g = rgb[1] - b = rgb[2] + if len(list(rgb)) < 3: + r = g = b = rgb[0] + else: + r = rgb[0] + g = rgb[1] + b = rgb[2] + return (r << 16) + (g << 8) + b +def bgr_to_hex(bgr): + return rgb_to_hex((bgr[0], 0, 0)) if len(list(bgr)) < 3 else rgb_to_hex((bgr[2], bgr[1], bgr[0])) + def color_distance_squared(c1, c2): - dr = c1[0] - c2[0] - dg = c1[1] - c2[1] - db = c1[2] - c2[2] - return dr * dr + dg * dg + db * db + d1 = abs(c1[0] - c2[0]) + d2 = abs(c1[1] - c2[1]) + d3 = abs(c1[2] - c2[2]) + return d1 * d1 + d2 * d2 + d3 * d3 class AnsiPixel: def __init__(self, pixel_u32, palette): - self.irc = self.nearest_hex_color(pixel_u32, palette) + self.irc = self.nearest_hex_color(pixel_u32, palette) def nearest_hex_color(self, pixel_u32, hex_colors): rgb_colors = [hex_to_rgb(color) for color in hex_colors] diff --git a/scroll.py b/scroll.py index 7621dd9..e7f7945 100644 --- a/scroll.py +++ b/scroll.py @@ -7,6 +7,7 @@ import json import random import re import ssl +import sys import time import urllib.request @@ -15,7 +16,7 @@ class connection: port = 6697 ipv6 = False ssl = True - vhost = None + vhost = None # Must in ('ip', port) format channel = '#chats' key = None modes = 'BdDg' @@ -85,17 +86,15 @@ class Bot(): self.host = '' self.playing = False self.settings = { - 'flood' : 1, - 'ignore' : 'big,birds,doc,gorf,hang,nazi,pokemon', - 'lines' : 500, - 'msg' : 0.03, - 'paste' : True, - 'png_brightness' : 0, - 'png_contrast' : 0, - 'png_effect' : None, - 'png_palette' : 'RGB99', - 'png_width' : 80, - 'results' : 25} + 'flood' : 1, + 'ignore' : 'big,birds,doc,gorf,hang,nazi,pokemon', + 'lines' : 500, + 'msg' : 0.03, + 'paste' : True, + 'png_palette' : 'RGB99', + 'png_quantize_colors' : 99, + 'png_width' : 80, + 'results' : 25} self.slow = False self.reader = None self.writer = None @@ -163,27 +162,47 @@ class Bot(): finally: self.db = cache - async def play(self, chan, name, paste=None): try: - if paste: + content = get_url(url).read() + except Exception as ex: + await self.irc_error(chan, 'failed to convert image', ex) + else: + if ascii: + if len(ascii) <= self.settings['lines']: + for line in ascii: + await self.sendmsg(chan, line) + await asyncio.sleep(self.settings['msg']) + else: + await self.irc_error('image is too big', 'take it to #scroll') + + + async def play(self, chan, name, img=False, paste=False): + try: + if img or paste: ascii = get_url(name) else: ascii = get_url(f'https://raw.githubusercontent.com/ircart/ircart/master/ircart/{name}.txt') if ascii.getcode() == 200: - ascii = ascii.readlines() + if img: + ascii = img2irc.convert(ascii.read(), img, int(self.settings['png_width']), self.settings['png_palette'], int(self.settings['png_quantize_colors'])) + else: + ascii = ascii.readlines() if len(ascii) > int(self.settings['lines']) and chan != '#scroll': await self.irc_error(chan, 'file is too big', f'take those {len(ascii):,} lines to #scroll') else: - await self.action(chan, 'the ascii gods have chosen... ' + color(name, cyan)) + if not img and not paste: + await self.action(chan, 'the ascii gods have chosen... ' + color(name, cyan)) for line in ascii: - try: - line = line.decode() - except: - line = line.encode(chardet.detect(line)['encoding']).decode() # Get fucked UTF-16 - await self.sendmsg(chan, line.replace('\n','').replace('\r','') + reset) + if type(line) == bytes: + try: + line = line.decode() + except UnicodeError: + line = line.decode(chardet.detect(line)['encoding']).encode().decode() # TODO: Do we need to re-encode/decode in UTF-8? + line = line.replace('\n','').replace('\r','') + await self.sendmsg(chan, line + reset) await asyncio.sleep(self.settings['msg']) else: - await self.irc_error(chan, 'invalid name', name) + await self.irc_error(chan, 'invalid name', name) if not img and not paste else await self.irc_error(chan, 'invalid url', name) except Exception as ex: try: await self.irc_error(chan, 'error in play function', ex) @@ -263,28 +282,25 @@ class Bot(): await asyncio.sleep(self.settings['msg']) elif args[1] == 'img' and len(args) == 3: url = args[2] - width = 512 - len(line.split(' :')[0])+4 if url.startswith('https://') or url.startswith('http://'): - try: - content = get_url(url).read() - ascii = img2irc.convert(content, 512 - len(f":{identity.nickname}!{identity.username}@{self.host} PRIVMSG {chan} :\r\n"), int(self.settings['png_width']), self.settings['png_palette'], self.settings['png_brightness'], self.settings['png_contrast'], self.settings['png_effect']) - except Exception as ex: - await self.irc_error(chan, 'failed to convert image', ex) - else: - if ascii: - if len(ascii) <= self.settings['lines']: - for line in ascii: - await self.sendmsg(chan, line) - await asyncio.sleep(self.settings['msg']) - else: - await self.irc_error('image is too big', 'take it to #scroll') + self.playing = True + width = 512 - len(line.split(' :')[0])+4 + self.loops[chan] = asyncio.create_task(self.play(chan, url, img=width)) elif msg == '.ascii list': await self.sendmsg(chan, underline + color('https://raw.githubusercontent.com/ircart/ircart/master/ircart/.list', light_blue)) - elif msg == '.ascii random': - self.playing = True - dir = random.choice([item for item in self.db if item not in self.settings['ignore']]) - ascii = f'{dir}/{random.choice(self.db[dir])}' - self.loops[chan] = asyncio.create_task(self.play(chan, ascii)) + elif args[1] == 'random' and len(args) in (2,3): + if len(args) == 3: + dir = args[2] + else: + random.seed(random.randrange(sys.maxsize)) + random.choice([item for item in self.db if item not in self.settings['ignore']]) + if dir in self.db: + random.seed(random.randrange(sys.maxsize)) + ascii = f'{dir}/{random.choice(self.db[dir])}' + self.playing = True + self.loops[chan] = asyncio.create_task(self.play(chan, ascii)) + else: + await self.irc_error(chan, 'invalid directory name', dir) elif msg == '.ascii sync' and is_admin(ident): await self.sync() await self.sendmsg(chan, bold + color('database synced', light_green)) @@ -294,14 +310,6 @@ class Bot(): self.loops[chan] = asyncio.create_task(self.play(chan, url, paste=True)) else: await self.irc_error(chan, 'invalid pastebin url', paste) - elif args[1] == 'random' and len(args) == 3: - dir = args[2] - if dir in self.db: - self.playing = True - ascii = f'{dir}/{random.choice(self.db[dir])}' - self.loops[chan] = asyncio.create_task(self.play(chan, ascii)) - else: - await self.irc_error(chan, 'invalid directory name', dir) elif args[1] == 'search' and len(args) == 3: query = args[2] results = [{'name':ascii,'dir':dir} for dir in self.db for ascii in self.db[dir] if query in ascii] @@ -322,7 +330,7 @@ class Bot(): setting = args[2] option = args[3] if setting in self.settings: - if setting in ('flood','lines','msg','png_brightness','png_contrast','png_width','results'): + if setting in ('flood','lines','msg','png_quantize_colors','png_width','results'): try: option = float(option) self.settings[setting] = option @@ -338,11 +346,6 @@ class Bot(): await self.sendmsg(chan, color('OK', light_green)) else: await self.irc_error(chan, 'invalid option', 'must be on or off') - elif setting == 'png_effect' and option in ('false','none','off','0'): - self.settings[setting] = None - else: - self.settings[setting] = option - await self.sendmsg(chan, color('OK', light_green)) else: await self.irc_error(chan, 'invalid setting', setting) elif len(args) == 2: @@ -378,4 +381,5 @@ try: import img2irc except ImportError: raise SystemExit('missing required \'img2irc\' file (https://github.com/ircart/scroll/blob/master/img2irc.py)') + pass asyncio.run(Bot().connect())