scroll

- irc bot to play ascii art
git clone git://git.acid.vegas/scroll.git
Log | Files | Refs | Archive | README | LICENSE

commit 6566bce064dfa4dcd1b773c878e54450ffa86424
parent f2f015c7f6693aada6b2cc318fc7e777df05a724
Author: acidvegas <acid.vegas@acid.vegas>
Date: Mon, 26 Jun 2023 05:32:13 -0400

img2irc improvements (props wrk) and fixed img_width

Diffstat:
A__pycache__/img2irc.cpython-39.pyc | 0
Mimg2irc.py | 77++++++++++++++++++++++++++++++++++++-----------------------------------------
Mscroll.py | 14+++++++++++++-

3 files changed, 49 insertions(+), 42 deletions(-)

diff --git a/__pycache__/img2irc.cpython-39.pyc b/__pycache__/img2irc.cpython-39.pyc
Binary files differ.
diff --git a/img2irc.py b/img2irc.py
@@ -17,40 +17,54 @@ try:
 except ImportError:
 	raise SystemExit('missing required \'pillow\' library (https://pypi.org/project/pillow/)')
 
-async def convert(data, img_width=80):
+def convert(data, max_line_len, img_width=80):
 	image = Image.open(io.BytesIO(data))
 	del data
+	return convert_image(image, max_line_len, img_width)
+
+def convert_image(image, max_line_len, img_width):
 	(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, img_width
-	ansi_image = AnsiImage(image)
-	del image
+	del img_height
 	CHAR = '\u2580'
-	buf = ''
-	for (y, row) in enumerate(ansi_image.halfblocks):
-		last_fg = -1
-		last_bg = -1
-		for (x, pixel_pair) in enumerate(row):
+	buf = list()
+	print(image.size)
+	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])]]
+		else:
+			bitmap = [[rgb_to_hex(image.getpixel((x, y))) for x in range(image.size[0])] for y in [i, i+1]]
+		top_row = [AnsiPixel(px) for px in bitmap[0]]
+		bottom_row = [AnsiPixel(px) for px in bitmap[1]]
+		buf += [""]
+		last_fg = last_bg = -1
+		ansi_row = list()
+		for j in range(image.size[0]):
+			top_pixel = top_row[j]
+			bottom_pixel = bottom_row[j]
+			pixel_pair = AnsiPixelPair(top_pixel, bottom_pixel)
 			fg = pixel_pair.top.irc
 			bg = pixel_pair.bottom.irc
-			if x != 0:
+			if j != 0:
 				if fg == last_fg and bg == last_bg:
-					buf += CHAR
+					buf[-1] += CHAR
 				elif bg == last_bg:
-					buf += f'\x03{fg}{CHAR}'
+					buf[-1] += f'\x03{fg}{CHAR}'
 				else:
-					buf += f'\x03{fg},{bg}{CHAR}'
+					buf[-1] += f'\x03{fg},{bg}{CHAR}'
 			else:
-				buf += f'\x03{fg},{bg}{CHAR}'
+				buf[-1] += f'\x03{fg},{bg}{CHAR}'
 			last_fg = fg
 			last_bg = bg
-		if y != len(ansi_image.halfblocks) - 1:
-			buf += '\n'
-		else:
-			buf += '\x0f'
-	return buf.splitlines()
+		print(len(buf[-1].encode('utf-8', 'ignore')), max_line_len)
+		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)
+	return buf
 
 def hex_to_rgb(color):
 	r = color >> 16
@@ -59,7 +73,9 @@ def hex_to_rgb(color):
 	return (r,g,b)
 
 def rgb_to_hex(rgb):
-	(r,g,b) = rgb
+	r = rgb[0]
+	g = rgb[1]
+	b = rgb[2]
 	return (r << 16) + (g << 8) + b
 
 def color_distance_squared(c1, c2):
@@ -97,23 +113,3 @@ class AnsiPixelPair:
 	def __init__(self, top, bottom):
 		self.top = top
 		self.bottom = bottom
-
-class AnsiImage:
-	def __init__(self, image):
-		self.bitmap = [[rgb_to_hex(image.getpixel((x, y))) for x in range(image.size[0])] for y in range(image.size[1])]
-		if len(self.bitmap) % 2 != 0:
-			self.bitmap.append([0 for x in range(image.size[0])])
-		ansi_bitmap = [[AnsiPixel(y) for y in x] for x in self.bitmap]
-		ansi_canvas = list()
-		for two_rows in range(0, len(ansi_bitmap), 2):
-			top_row = ansi_bitmap[two_rows]
-			bottom_row = ansi_bitmap[two_rows+1]
-			ansi_row = list()
-			for i in range(len(self.bitmap[0])):
-				top_pixel = top_row[i]
-				bottom_pixel = bottom_row[i]
-				pixel_pair = AnsiPixelPair(top_pixel, bottom_pixel)
-				ansi_row.append(pixel_pair)
-			ansi_canvas.append(ansi_row)
-		self.image = image
-		self.halfblocks = ansi_canvas
-\ No newline at end of file
diff --git a/scroll.py b/scroll.py
@@ -82,6 +82,7 @@ class Bot():
 		self.db              = None
 		self.last            = time.time()
 		self.loops           = dict()
+		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_width':80, 'results':25}
 		self.slow            = False
@@ -201,6 +202,11 @@ class Bot():
 					await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel)
 					await self.raw('JOIN #scroll')
 					await self.sync()
+				elif args[1] == '311' and len(args) >= 6: # RPL_WHOISUSER
+					nick = args[2]
+					host = args[5]
+					if nick == identity.nickname:
+						self.host = host
 				elif args[1] == '433':
 					error('The bot is already running or nick is in use.')
 				elif args[1] == 'INVITE' and len(args) == 4:
@@ -208,6 +214,11 @@ class Bot():
 					chan    = args[3][1:]
 					if invited == identity.nickname and chan in (connection.channel, '#scroll'):
 						await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel)
+				elif args[1] == 'JOIN' and len(args) >= 3:
+					nick = args[0].split('!')[0][1:]
+					host = args[0].split('@')[1]
+					if nick == identity.nickname:
+						self.host = host
 				elif args[1] == 'KICK' and len(args) >= 4:
 					chan   = args[2]
 					kicked = args[3]
@@ -241,10 +252,11 @@ 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   = await img2irc.convert(content, int(self.settings['png_width']))
+											ascii   = await img2irc.convert(content, 512 - len(f":{identity.nickname}!{identity.username}@{self.host} PRIVMSG {chan} :\r\n"), int(self.settings['png_width']))
 										except Exception as ex:
 											await self.irc_error(chan, 'failed to convert image', ex)
 										else: