Update ASCII plugin

This commit is contained in:
Pedro de Oliveira 2019-12-05 21:40:08 +00:00
parent 23af1cca99
commit 655dbf7e58
4 changed files with 1782 additions and 1817 deletions

View File

@ -1,6 +1,9 @@
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=T8E56M6SP9JH2)
Try the plugin out in #ircart on EFnet. irc://irc.efnet.org/#ircart
<b>ASCII Art Plugin</b><br>
Convert text to ASCII art or image URLs to ASCII/ANSI art. Covert ASCII art to PNG. Get ASCII weather, moon phase, and cryptocurrecy rates.
@ -103,14 +106,15 @@ img --bg <0-99> <url> (set a background color)
img --fg <0-99> <url> (set a foreground color)
img --fast <url> (use Euclidean color difference.)
img --slow <url> (use cie2000 color difference. best quality, default)
img --dither <url> (dither source image to 256 colors. trades off quality for speed)
img --quantize <url> (quantize source image to 256 colors. trades off quality for speed)
img --no-quantize <url> (don't quantize source to 256 colors)
```
Here are some images using 99 color default output:
![Image of Img Command Output](https://i.imgur.com/33tCGXC.png)<br>
![Image of Img Command Output](https://i.imgur.com/NrMaQdg.png)<br>
^ output of img https://i.imgur.com/aF9wihd.jpg (image command with default settings)
![Image of Img Command Output](https://i.imgur.com/2BSUjnw.png)<br>
![Image of Img Command Output](https://i.imgur.com/ydNaDKc.png)<br>
^ output of img --block https://i.imgur.com/aF9wihd.jpg (image command with colored space blocks)
![Image of Img Command Output](https://i.imgur.com/eOQAzTo.png)<br>
![Image of Img Command Output](https://i.imgur.com/Q2lsg3H.png)<br>
^ output of img --ascii https://i.imgur.com/aF9wihd.jpg (image command with colored space blocks)
```
***************+*++++++++++++++++++++++++++++++++++++++=++=++========================---------------

View File

@ -17,14 +17,15 @@ import supybot.world as world
__version__ = ""
# XXX Replace this with an appropriate author or supybot.Author instance.
__author__ = supybot.authors.unknown
__author__ = supybot.Author('oddluck', 'oddluck',
'oddluck@riseup.net')
# This is a dictionary mapping supybot.Author instances to lists of
# contributions.
__contributors__ = {}
# This is a url where the most recent plugin package can be downloaded.
__url__ = ''
__url__ = 'https://github.com/oddluck/limnoria-plugins/'
from . import config
from . import plugin

View File

@ -38,8 +38,11 @@ registry.Boolean(False, _("""Turns on and off paste.ee support""")))
conf.registerChannelValue(ASCII, 'delay',
registry.Float(1.0, _("""Set the time delay betwen lines. Not currently implemented.""")))
conf.registerChannelValue(ASCII, 'dither',
registry.Boolean(True, _("""Enable dithering. Results in much faster rendering at a slight decrease in quality. Default: True""")))
conf.registerChannelValue(ASCII, 'quantize',
registry.Boolean(False, _("""Enable quantizing to 256 colors before rendering. Results in much faster rendering at a slight decrease in quality. Default: False""")))
conf.registerChannelValue(ASCII, 'resize',
registry.Integer(3, _("""Set the resize algorithm. 0 = nearest, 1 = lanczos, 2 = bilinear, 3 = bicubic, 4 = box, 5 = hamming""")))
conf.registerChannelValue(ASCII, 'speed',
registry.String('Slow', _("""Set the speed of the color rendering. 'Slow' (default) to use CIEDE2000 color difference. 'Fast' to use Euclidean color difference.""")))
@ -51,7 +54,13 @@ conf.registerChannelValue(ASCII, 'asciiWidth',
registry.Integer(100, _("""Set the default column width for ascii art images""")))
conf.registerChannelValue(ASCII, 'blockWidth',
registry.Integer(70, _("""Set the default column width for 1/2 and 1/4 block art images""")))
registry.Integer(80, _("""Set the default column width for 1/2 and 1/4 block art images""")))
conf.registerChannelValue(ASCII, 'colors',
registry.Integer(99, _("""Set the default number of colors to use. Options are 16 for colors 0-15 only, 83 for colors 16-98 only, and 99 (default) to use all available colors""")))
conf.registerChannelValue(ASCII, 'fg',
registry.Integer(99, _("""Set the default foreground color for ascii art images. 0-98. 99 is disabled (default)""")))
conf.registerChannelValue(ASCII, 'bg',
registry.Integer(99, _("""Set the default background color for ascii art images. 0-98. 99 is disabled (default)""")))

View File

@ -10,6 +10,7 @@ import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.ircdb as ircdb
import supybot.callbacks as callbacks
import supybot.ircmsgs as ircmsgs
import os
@ -343,15 +344,15 @@ class ASCII(callbacks.Plugin):
self.x256colors83 = [88,28,32,30,36,38,34,96,94,52,56,54,60,62,58,98,88,36,36,48,48,60,32,34,47,47,47,72,32,33,34,59,59,59,44,45,45,46,71,71,44,68,45,69,46,83,56,68,57,57,69,58,28,38,37,49,49,60,30,93,47,72,72,72,31,33,34,59,59,59,43,45,45,46,71,71,56,68,57,69,70,83,56,68,68,57,69,70,28,39,38,49,49,61,41,93,50,50,72,72,30,30,94,84,84,84,43,43,45,46,71,71,43,68,80,81,82,83,55,68,68,80,81,70,40,51,51,50,50,61,41,64,63,50,73,73,30,41,76,87,85,84,42,42,95,96,84,84,55,67,79,81,82,83,55,67,80,80,81,82,40,51,51,50,50,73,41,64,63,75,62,73,53,53,76,87,85,85,42,65,77,76,87,85,42,66,78,78,97,97,55,67,79,79,81,82,52,64,63,63,62,62,52,64,63,75,75,74,53,64,76,87,87,86,65,65,65,76,87,86,54,77,77,77,97,86,54,66,66,78,78,98,88,89,89,90,91,91,92,92,92,93,93,94,94,94,95,95,95,96,96,96,97,97,97,97]
self.x16colors = {
'30':'01',
'31':'04',
'31':'05',
'32':'03',
'33':'08',
'33':'07',
'34':'02',
'35':'06',
'36':'10',
'37':'15',
'30;1':'14',
'31;1':'07',
'31;1':'04',
'32;1':'09',
'33;1':'08',
'34;1':'12',
@ -359,15 +360,15 @@ class ASCII(callbacks.Plugin):
'36;1':'11',
'37;1':'00',
'40':'01',
'41':'04',
'41':'05',
'42':'03',
'43':'08',
'43':'07',
'44':'02',
'45':'06',
'46':'10',
'47':'15',
'40;1':'14',
'41;1':'07',
'41;1':'04',
'42;1':'09',
'43;1':'08',
'44;1':'12',
@ -464,117 +465,92 @@ class ASCII(callbacks.Plugin):
return self.matches[pixel]
def rgb2lab (self, inputColor) :
num = 0
RGB = [0, 0, 0]
for value in inputColor :
value = float(value) / 255
if value > 0.04045 :
value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
else :
value = value / 12.92
RGB[num] = value * 100
num = num + 1
XYZ = [0, 0, 0,]
X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
XYZ[ 0 ] = round( X, 4 )
XYZ[ 1 ] = round( Y, 4 )
XYZ[ 2 ] = round( Z, 4 )
XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047 # ref_X = 95.047 Observer= 2°, Illuminant= D65
XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0 # ref_Y = 100.000
XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883 # ref_Z = 108.883
num = 0
for value in XYZ :
if value > 0.008856 :
value = value ** ( 0.3333333333333333 )
else :
value = ( 7.787 * value ) + ( 16 / 116 )
XYZ[num] = value
num = num + 1
Lab = [0, 0, 0]
L = ( 116 * XYZ[ 1 ] ) - 16
a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )
Lab [ 0 ] = round( L, 4 )
Lab [ 1 ] = round( a, 4 )
Lab [ 2 ] = round( b, 4 )
return Lab
try:
return self.labmatches[inputColor]
except:
num = 0
RGB = [0, 0, 0]
for value in inputColor :
value = float(value) / 255
if value > 0.04045 :
value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
else :
value = value / 12.92
RGB[num] = value * 100
num = num + 1
XYZ = [0, 0, 0,]
X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
XYZ[ 0 ] = round( X, 4 )
XYZ[ 1 ] = round( Y, 4 )
XYZ[ 2 ] = round( Z, 4 )
XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047 # ref_X = 95.047 Observer= 2°, Illuminant= D65
XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0 # ref_Y = 100.000
XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883 # ref_Z = 108.883
num = 0
for value in XYZ :
if value > 0.008856 :
value = value ** ( 0.3333333333333333 )
else :
value = ( 7.787 * value ) + ( 16 / 116 )
XYZ[num] = value
num = num + 1
Lab = [0, 0, 0]
L = ( 116 * XYZ[ 1 ] ) - 16
a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )
Lab [ 0 ] = round( L, 4 )
Lab [ 1 ] = round( a, 4 )
Lab [ 2 ] = round( b, 4 )
self.labmatches[inputColor] = Lab
return self.labmatches[inputColor]
def ciede2000(self, color1, color2):
"""
Calculates color difference according to the `CIEDE 2000`_ formula. This is
the most accurate algorithm currently implemented but also the most complex
and slowest. Like CIE1994 it is largely based in CIE L*C*h* space, but with
several modifications to account for perceptual uniformity flaws.
.. _CIEDE 2000: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000
"""
# See WP article and Sharma 2005 for important implementation notes:
# http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
#
# Yes, there's lots of locals; but this is easiest to understand as it's a
# near straight translation of the math
# pylint: disable=too-many-locals
C_ = (
math.sqrt(color1[1] ** 2 + color1[2] ** 2) +
math.sqrt(color2[1] ** 2 + color2[2] ** 2)
) / 2
G = (1 - math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7))) / 2
a1_prime = (1 + G) * color1[1]
a2_prime = (1 + G) * color2[1]
C1_prime = math.sqrt(a1_prime ** 2 + color1[2] ** 2)
C2_prime = math.sqrt(a2_prime ** 2 + color2[2] ** 2)
L_ = (color1[0] + color2[0]) / 2
C_ = (C1_prime + C2_prime) / 2
h1 = (
0.0 if color1[2] == a1_prime == 0 else
math.degrees(math.atan2(color1[2], a1_prime)) % 360
)
h2 = (
0.0 if color2[2] == a2_prime == 0 else
math.degrees(math.atan2(color2[2], a2_prime)) % 360
)
if C1_prime * C2_prime == 0.0:
dh = 0.0
h_ = h1 + h2
elif abs(h1 - h2) <= 180:
dh = h2 - h1
h_ = (h1 + h2) / 2
else:
if h2 > h1:
dh = h2 - h1 - 360
else:
dh = h2 - h1 + 360
if h1 + h2 >= 360:
h_ = (h1 + h2 - 360) / 2
else:
h_ = (h1 + h2 + 360) / 2
dL = color2[0] - color1[0]
dC = C2_prime - C1_prime
dH = 2 * math.sqrt(C1_prime * C2_prime) * math.sin(math.radians(dh / 2))
T = (
1 -
0.17 * math.cos(math.radians(h_ - 30)) +
0.24 * math.cos(math.radians(2 * h_)) +
0.32 * math.cos(math.radians(3 * h_ + 6)) -
0.20 * math.cos(math.radians(4 * h_ - 63))
)
SL = 1 + (0.015 * (L_ - 50) ** 2) / math.sqrt(20 + (L_ - 50) ** 2)
SC = 1 + 0.045 * C_
SH = 1 + 0.015 * C_ * T
RT = (
-2 * math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7)) *
math.sin(math.radians(60 * math.exp(-(((h_ - 275) / 25) ** 2))))
)
delta_e = math.sqrt(
(dL / SL) ** 2 +
(dC / SC) ** 2 +
(dH / SH) ** 2 +
RT * (dC / SC) * (dH / SH)
)
return delta_e
def ciede2000(self, lab1, lab2):
""" CIEDE2000 color difference formula. https://peteroupc.github.io/colorgen.html"""
dl=lab2[0]-lab1[0]
hl=lab1[0]+dl*0.5
sqb1=lab1[2]*lab1[2]
sqb2=lab2[2]*lab2[2]
c1=math.sqrt(lab1[1]*lab1[1]+sqb1)
c2=math.sqrt(lab2[1]*lab2[1]+sqb2)
hc7=math.pow((c1+c2)*0.5,7)
trc=math.sqrt(hc7/(hc7+6103515625))
t2=1.5-trc*0.5
ap1=lab1[1]*t2
ap2=lab2[1]*t2
c1=math.sqrt(ap1*ap1+sqb1)
c2=math.sqrt(ap2*ap2+sqb2)
dc=c2-c1
hc=c1+dc*0.5
hc7=math.pow(hc,7)
trc=math.sqrt(hc7/(hc7+6103515625))
h1=math.atan2(lab1[2],ap1)
if h1<0:
h1=h1+math.pi*2
h2=math.atan2(lab2[2],ap2)
if h2<0:
h2=h2+math.pi*2
hdiff=h2-h1
hh=h1+h2
if abs(hdiff)>math.pi:
hh=hh+math.pi*2
if h2<=h1:
hdiff=hdiff+math.pi*2
else:
hdiff=hdiff-math.pi*2
hh=hh*0.5
t2=1-0.17*math.cos(hh-math.pi/6)+0.24*math.cos(hh*2)
t2=t2+0.32*math.cos(hh*3+math.pi/30)
t2=t2-0.2*math.cos(hh*4-math.pi*63/180)
dh=2*math.sqrt(c1*c2)*math.sin(hdiff*0.5)
sqhl=(hl-50)*(hl-50)
fl=dl/(1+(0.015*sqhl/math.sqrt(20+sqhl)))
fc=dc/(hc*0.045+1)
fh=dh/(t2*hc*0.015+1)
dt=30*math.exp(-math.pow(36*hh-55*math.pi,2)/(25*math.pi*math.pi))
r=-2*trc*math.sin(2*dt*math.pi/180)
return math.sqrt(fl*fl+fc*fc+fh*fh+r*fc*fh)
def distance(self, c1, c2, speed):
if speed == 'fast':
@ -619,12 +595,12 @@ class ASCII(callbacks.Plugin):
continue
elif int(ansi[i]) > 29 and int(ansi[i]) < 38:
if effect == 1 or ansi[-1] == '1':
x16color2 = self.x16colors['{0};1'.format(ansi[i])]
x16color1 = self.x16colors['{0};1'.format(ansi[i])]
effect = None
i += 1
continue
else:
x16color2 = self.x16colors[ansi[i]]
x16color1 = self.x16colors[ansi[i]]
i += 1
continue
elif int(ansi[i]) > 39 and int(ansi[i]) < 48:
@ -690,9 +666,11 @@ class ASCII(callbacks.Plugin):
return ''
def ansi2irc(self, output):
output = output.replace('\x1b[0m\x1b', '\x1b')
output = output.replace('\x1b(B\x1b[m', '\x1b[0m')
output = output.replace('\x1b\x1b', '\x1b')
output = re.sub(r'\x1B\[[0-?]*[ -/]*[@-~]', lambda m: self.process_ansi(m.group(0)), output)
output = re.sub('\x0399,(\d\d)\x03(\d\d)', '\x03\g<2>,\g<1>', output)
output = output.replace('\x0F\x03', '\x03')
return output
def png(self, irc, msg, args, optlist, url):
@ -718,7 +696,11 @@ class ASCII(callbacks.Plugin):
else:
irc.reply("Invalid file type.", private=False, notice=False)
return
file = file.content.decode()
try:
file = file.content.decode()
except:
file = file.content.decode('cp437')
file = re.sub('(\x03(\d+).*)\x03,', '\g<1>\x03\g<2>,', file).replace('\r\n','\n')
im, x, y = self.renderImage(file, 18, bg, fg)
path = os.path.dirname(os.path.abspath(__file__))
filepath = "{0}/tmp/tldr.png".format(path)
@ -795,7 +777,7 @@ class ASCII(callbacks.Plugin):
fontlist = wrap(fontlist)
def img(self, irc, msg, args, channel, optlist, url):
"""[<#channel>] [--delay #.#] [--w <###>] [--s <#.#] [--16] [--99] [--83] [--ascii] [--block] [--1/2] [--1/4] [--chars <text>] [--ramp <text>] [--bg <0-98>] [--fg <0-98>] [--no-color] [--invert] [--dither] [--no-dither] <url>
"""[<#channel>] [--delay #.#] [--w <###>] [--s <#.#] [--16] [--99] [--83] [--ascii] [--block] [--1/2] [--chars <text>] [--ramp <text>] [--bg <0-98>] [--fg <0-98>] [--no-color] [--invert] <url>
Image to ASCII Art.
--w columns.
--s saturation (1.0).
@ -804,7 +786,6 @@ class ASCII(callbacks.Plugin):
--83 colors 16-98.
--ascii color ascii.
--block space block.
--1/4 for 1/4 block.
--1/2 for 1/2 block
--chars <TEXT> color text.
--ramp <TEXT> set ramp (".:-=+*#%@").
@ -812,11 +793,12 @@ class ASCII(callbacks.Plugin):
--fg <0-99> set fg.
--no-color greyscale ascii.
--invert inverts ramp.
--dither to reduce source colors.
--no-dither for no color reduction.
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
gscale = "\xa0"
if '16' in optlist:
@ -837,20 +819,20 @@ class ASCII(callbacks.Plugin):
delay = optlist.get('delay')
else:
delay = self.registryValue('delay', msg.args[0])
if 'dither' in optlist:
dither = True
elif 'no-dither' in optlist:
dither = False
if 'quantize' in optlist:
quantize = True
elif 'no-quantize' in optlist:
quantize = False
else:
dither = self.registryValue('dither', msg.args[0])
quantize = self.registryValue('quantize', msg.args[0])
if 'bg' in optlist:
bg = optlist.get('bg')
else:
bg = 1
bg = self.registryValue('bg', msg.args[0])
if 'fg' in optlist:
fg = optlist.get('fg')
else:
fg = 99
fg = self.registryValue('fg', msg.args[0])
if 'chars' in optlist:
type = 'ascii'
gscale = optlist.get('chars')
@ -863,8 +845,6 @@ class ASCII(callbacks.Plugin):
elif 'ascii' in optlist:
type = 'ascii'
gscale = ".'`^\":;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
elif '1/4' in optlist:
type = '1/4'
elif '1/2' in optlist:
type = '1/2'
elif 'block' in optlist:
@ -890,8 +870,6 @@ class ASCII(callbacks.Plugin):
cols = self.registryValue('asciiWidth', msg.args[0])
else:
cols = self.registryValue('blockWidth', msg.args[0])
if type == '1/4':
cols = cols * 2
if 's' in optlist:
s = float(optlist.get('s'))
path = os.path.dirname(os.path.abspath(__file__))
@ -912,7 +890,11 @@ class ASCII(callbacks.Plugin):
# open image and convert to grayscale
image = Image.open(filename)
if image.mode == 'RGBA':
image = Image.alpha_composite(Image.new("RGBA", image.size, self.rgbColors[bg] + (255,)), image)
if bg == 99:
newbg = 1
else:
newbg = bg
image = Image.alpha_composite(Image.new("RGBA", image.size, self.rgbColors[newbg] + (255,)), image)
if image.mode != 'RGB':
image = image.convert('RGB')
try:
@ -931,16 +913,20 @@ class ASCII(callbacks.Plugin):
h = w/scale
# compute number of rows
rows = int(H/h)
image = ImageOps.autocontrast(image)
if 'resize' in optlist:
resize = optlist.get('resize')
else:
resize = self.registryValue('resize', msg.args[0])
if type != 'no-color':
image2 = image.resize((cols, rows), Image.LANCZOS)
image2 = image.resize((cols, rows), resize)
if 's' in optlist:
image2 = ImageEnhance.Color(image2).enhance(s)
if dither:
image2 = image2.convert('P', palette=Image.ADAPTIVE)
if quantize:
image2 = image2.quantize(dither=None)
image2 = image2.convert('RGB')
colormap = np.array(image2)
self.matches = {}
self.labmatches = {}
# ascii image is a list of character strings
aimg = []
if type == '1/2':
@ -948,154 +934,111 @@ class ASCII(callbacks.Plugin):
for j in range(0, rows - 1, 2):
# append an empty string
aimg.append("")
old_color = "99,99"
old_color1 = "99"
old_color2 = "99"
old_char = None
for i in range(cols):
color1 = '%02d' % self.getColor(colormap[j][i].tolist(), speed)
color2 = '%02d' % self.getColor(colormap[j+1][i].tolist(), speed)
color = "{0},{1}".format(color1, color2)
if color != old_color:
if color1 == color2:
gsval = " "
color = "0,{0}".format(color1)
else:
gsval = ""
alt_gsval = ""
if gsval != " " and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]) and 'tops' not in optlist:
aimg[k] += alt_gsval
elif gsval == " " and "{0}".format(color1) == "{0}".format(old_color.split(',')[1]):
aimg[k] += " "
else:
aimg[k] += "\x03{0}{1}".format(color, gsval)
old_color = color
else:
if color1 == color2:
aimg[k] += " "
else:
aimg[k] += ""
for i in range(0,98):
i = '%02d' % i
aimg[k] = re.sub("\x030,{0}(\s+)\x03(\d\d),{0}".format(i), "\x03\g<2>,{0}\g<1>".format(i), aimg[k])
for i in range(0,98):
i = '%02d' % i
aimg[k] = aimg[k].replace("{0}".format(i), "{0}".format(int(i)))
k += 1
elif type == '1/4':
k = 0
for j in range(0, rows - 1, 2):
# append an empty string
aimg.append("")
old_color = "99,99"
for i in range(0, cols - 1, 2):
color1 = '%02d' % self.getColor(colormap[j][i].tolist(), speed)
color2 = '%02d' % self.getColor(colormap[j+1][i].tolist(), speed)
color3 = '%02d' % self.getColor(colormap[j][i+1].tolist(), speed)
color4 = '%02d' % self.getColor(colormap[j+1][i+1].tolist(), speed)
if color1 == color2 and color1 == color3 and color1 == color4:
if color1 == color2:
gsval = " "
color = "0,{0}".format(color1)
elif color1 == color4 and color2 == color3:
gsval = ""
color = "{0},{1}".format(color1, color2)
elif color1 == color2 and color1 == color3 and color1 != color4:
gsval = ""
color = "{0},{1}".format(color1, color4)
elif color3 == color4 and color2 == color4 and color3 != color1:
gsval = ""
color = "{0},{1}".format(color2, color1)
elif color1 == color2 and color1 == color4 and color1 != color3:
gsval = ""
color = "{0},{1}".format(color1, color3)
elif color1 == color3 and color1 == color4 and color1 != color2:
gsval = ""
color = "{0},{1}".format(color1, color2)
elif color1 == color3 and color2 == color4 and color1 != color2 and color3 != color4:
else:
gsval = ""
color = "{0},{1}".format(color1, color4)
elif color1 == color2 and color3 == color4 and color1 != color3 and color2 != color4:
gsval = ""
color = "{0},{1}".format(color1, color4)
else:
row1 = '%02d' % self.getColor(np.average([tuple(colormap[j][i].tolist()), tuple(colormap[j][i+1].tolist())], axis=0).tolist(), speed)
row2 = '%02d' % self.getColor(np.average([tuple(colormap[j+1][i+1].tolist()), tuple(colormap[j][i+1].tolist())], axis=0).tolist(), speed)
if row2 == color1 and row2 != color3:
gsval = ""
color = "{0},{1}".format(row2, color3)
elif row1 == color2 and row1 != color4:
gsval = ""
color = "{0},{1}".format(row1, color4)
elif row2 == color3 and row2 != color1:
gsval = ""
color = "{0},{1}".format(row2, color1)
elif row1 == color4 and row1 != color2:
gsval = ""
color = "{0},{1}".format(row1, color2)
if color1 == old_color1 and color2 == old_color2:
aimg[k] += gsval
old_char = gsval
elif gsval == " " and color1 == old_color2:
aimg[k] += " "
old_char = gsval
elif gsval == " " and color1 == old_color1 and old_char == '':
aimg[k] = aimg[k][:-1]
aimg[k] += "\x0301,{0} ".format(color1)
old_color1 = "01"
old_color2 = color1
old_char = gsval
elif gsval == " " and color1 == old_color1 and old_char == '^█':
aimg[k] = aimg[k][:-4]
aimg[k] += "\x0301,{0} ".format(color1)
old_color1 = "01"
old_color2 = color1
old_char = gsval
elif gsval == " " and color1 == old_color1 and old_char == "^^▀" and 'tops' not in optlist:
aimg[k] = aimg[k][:-7]
aimg[k] += "\x03{0},{1}".format(old_color2, color1)
old_color1 = old_color2
old_color2 = color1
old_char = gsval
elif gsval == " " and color1 == old_color1 and old_char != '' and 'tops' not in optlist:
aimg[k] += ""
old_char = ''
elif gsval == " " and 'tops' not in optlist:
aimg[k] += "\x03{0}".format(color1)
old_color1 = color1
old_char = '^█'
elif gsval != " " and color1 == old_color1 and old_char == '^█' and 'tops' not in optlist:
aimg[k] = aimg[k][:-4]
aimg[k] += "\x03{0},{1}".format(color2, color1)
old_color1 = color2
old_color2 = color1
old_char = ''
elif gsval != " " and color2 == old_color1 and old_char == '^█':
aimg[k] = aimg[k][:-4]
aimg[k] += "\x03{0},{1}".format(color1, color2)
old_color1 = color1
old_color2 = color2
old_char = gsval
elif gsval != " " and color1 == old_color2 and color2 == old_color1 and old_char == "^^▀" and 'tops' not in optlist:
aimg[k] = aimg[k][:-7]
aimg[k] += "\x03{0},{1}▄▀".format(color1, color2)
old_color1 = color1
old_color2 = color2
old_char = gsval
elif gsval != " " and color1 == old_color1 and color2 != old_color2 and old_char == "^^▀" and 'tops' not in optlist:
aimg[k] = aimg[k][:-7]
aimg[k] += "\x03{0},{1}\x03{2}".format(old_color2, color1, color2)
old_color1 = color2
old_color2 = color1
old_char = ''
elif gsval != " " and color1 == old_color1 and color2 != old_color2 and old_char == "^▀" and 'tops' not in optlist:
aimg[k] = aimg[k][:-4]
aimg[k] += "\x03{0},{1}\x03{2}".format(old_color2, color1, color2)
old_color1 = color2
old_color2 = color1
old_char = ''
elif gsval != " " and color1 == old_color2 and color2 == old_color1 and 'tops' not in optlist:
aimg[k] += ""
old_char = ''
elif gsval != " " and color1 == old_color2 and 'tops' not in optlist:
aimg[k] += "\x03{0}".format(color2)
old_color1 = color2
old_char = ''
elif color1 != old_color1 and color2 == old_color2:
aimg[k] += "\x03{0}{1}".format(color1, gsval)
old_color1 = color1
if gsval == ' ':
old_char = gsval
else:
col1 = '%02d' % self.getColor(np.average([tuple(colormap[j][i].tolist()), tuple(colormap[j+1][i].tolist())], axis=0).tolist(), speed)
col2 = '%02d' % self.getColor(np.average([tuple(colormap[j][i+1].tolist()), tuple(colormap[j+1][i+1].tolist())], axis=0).tolist(), speed)
if col1 == color4 and col1 != color3:
gsval = ""
color = "{0},{1}".format(col1, color3)
elif col1 == color3 and col1 != color4:
gsval = ""
color = "{0},{1}".format(col1, color4)
elif col2 == color2 and col2 != color1:
gsval = ""
color = "{0},{1}".format(col2, color1)
elif col2 == color1 and col2 != color2:
gsval = ""
color = "{0},{1}".format(col2, color2)
elif row1 != row2:
gsval = ""
color = "{0},{1}".format(row1, row2)
elif col1 != col2:
gsval = ""
color = "{0},{1}".format(col1, col2)
elif row1 == row2:
gsval = " "
color = "0,{0}".format(row1)
elif col1 == col2:
gsval = " "
color = "0,{0}".format(col1)
if color != old_color:
if gsval == " " and "{0}".format(color.split(',')[1]) == "{0}".format(old_color.split(',')[1]):
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
elif gsval == "" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
gsval = ""
aimg[k] += "{0}".format(gsval)
else:
old_color = color
# append char to string
aimg[k] += "\x03{0}{1}".format(color, gsval)
old_char = '^▀'
else:
aimg[k] += "{0}".format(gsval)
for i in range(0,98):
i = '%02d' % i
aimg[k] = re.sub("\x030,{0}(\s+)\x03(\d\d),{0}".format(i), "\x03\g<2>,{0}\g<1>".format(i), aimg[k])
aimg[k] += "\x03{0},{1}{2}".format(color1, color2, gsval)
old_color1 = color1
old_color2 = color2
if gsval == ' ':
old_char = gsval
else:
old_char = '^^▀'
if 'tops' in optlist:
aimg[k] = re.sub("\x03\d\d,(\d\d\s+\x03)", "\x0301,\g<1>", aimg[k])
aimg[k] = re.sub("\x03\d\d,(\d\d\s+$)", "\x0301,\g<1>", aimg[k])
aimg[k] = re.sub("\x03\d\d,(\d\d\s\x03)", "\x0301,\g<1>", aimg[k])
aimg[k] = re.sub("\x0301,(\d\d)(\s+)\x03(\d\d)([^,])", "\x03\g<3>,\g<1>\g<2>\g<4>", aimg[k])
for i in range(0,98):
i = '%02d' % i
aimg[k] = aimg[k].replace("{0}".format(i), "{0}".format(int(i)))
k += 1
else:
if 'chars' not in optlist and gscale != '\xa0':
image = image.resize((cols, rows), Image.LANCZOS)
image = image.resize((cols, rows), resize)
image = image.convert('L')
lumamap = np.array(image)
# generate list of dimensions
@ -1121,10 +1064,27 @@ class ASCII(callbacks.Plugin):
else:
gsval = '\xa0'
# get color value
if type != 'no-color' and i == 0:
if type != 'no-color' and gscale != '\xa0' and i == 0:
color = self.getColor(colormap[j][i].tolist(), speed)
old_color = color
if 'bg' not in optlist:
if bg != 99:
color = "{0},{1}".format(color, "{:02d}".format(int(bg)))
if gsval != '\xa0':
aimg[j] += "\x03{0}{1}".format(color, gsval)
else:
aimg[j] += "\x030,{0} ".format(int(color))
elif type == 'no-color' and i == 0:
if bg != 99 and fg != 99:
aimg[j] += "\x03{0},{1}{2}".format("{:02d}".format(int(fg)), "{:02d}".format(int(bg)), gsval)
elif fg != 99:
aimg[j] += "\x03{0}{1}".format("{:02d}".format(int(fg)), gsval)
elif bg != 99:
aimg[j] += "\x03{0},{1}{2}".format("{:02d}".format(int(fg)), "{:02d}".format(int(bg)), gsval)
elif type != 'no-color' and gsval != ' ':
color = self.getColor(colormap[j][i].tolist(), speed)
if color != old_color:
old_color = color
# append ascii char to string
if gsval != '\xa0':
if gsval.isdigit():
color = "{:02d}".format(int(color))
@ -1133,56 +1093,14 @@ class ASCII(callbacks.Plugin):
aimg[j] += "\x03{0}{1}".format(int(color), gsval)
else:
aimg[j] += "\x030,{0} ".format(int(color))
else:
if gsval != '\xa0':
if gsval.isdigit():
newbg = "{:02d}".format(int(bg))
aimg[j] += "\x03{0},{1}{2}".format(int(color), newbg, gsval)
else:
aimg[j] += "\x03{0},{1}{2}".format(int(color), int(bg), gsval)
else:
aimg[j] += "\x030,{0} ".format(int(color))
elif type != 'no-color' and gsval != ' ':
color = self.getColor(colormap[j][i].tolist(), speed)
if color != old_color:
old_color = color
# append ascii char to string
if 'bg' not in optlist:
if gsval != '\xa0':
if gsval.isdigit():
color = "{:02d}".format(int(color))
aimg[j] += "\x03{0}{1}".format(color, gsval)
else:
aimg[j] += "\x03{0}{1}".format(int(color), gsval)
else:
aimg[j] += "\x030,{0} ".format(int(color))
else:
if gsval != '\xa0':
if gsval.isdigit():
newbg = "{:02d}".format(int(bg))
aimg[j] += "\x03{0},{1}{2}".format(int(color), newbg, gsval)
else:
aimg[j] += "\x03{0},{1}{2}".format(int(color), int(bg), gsval)
else:
aimg[j] += "\x030,{0} ".format(int(color))
else:
aimg[j] += "{0}".format(gsval)
else:
aimg[j] += "{0}".format(gsval)
# return txt image
output = aimg
paste = ""
self.stopped[msg.args[0]] = False
for line in output:
if type == 'no-color' and 'fg' in optlist and 'bg' in optlist:
newbg = "{:02d}".format(int(bg))
line = "\x03{0},{1}{2}".format(int(fg), newbg, line)
elif type == 'no-color' and 'fg' in optlist:
newfg = "{:02d}".format(int(fg))
line = "\x03{0}{1}".format(newfg, line)
elif type == 'no-color' and 'bg' in optlist:
newbg = "{:02d}".format(int(bg))
line = "\x0399,{0}{1}".format(newbg, line)
if self.registryValue('pasteEnable', msg.args[0]):
paste += line + "\n"
if not self.stopped[msg.args[0]]:
@ -1190,7 +1108,7 @@ class ASCII(callbacks.Plugin):
irc.reply(line, prefixNick=False, noLengthCheck=True, private=False, notice=False, to=channel)
if self.registryValue('pasteEnable', msg.args[0]):
irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', '16':'', '99':'', '83':'', 'delay':'float', 'dither':'', 'no-dither':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'no-color':'', 'block':'', 'ascii':'', '1/4':'', '1/2':'', 's':'float', 'tops':''}), ('text')])
img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', '16':'', '99':'', '83':'', 'delay':'float', 'resize':'int', 'quantize':'', 'no-quantize':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'no-color':'', 'block':'', 'ascii':'', '1/2':'', 's':'float', 'tops':''}), ('text')])
def scroll(self, irc, msg, args, channel, optlist, url):
"""[<channel>] [--delay] <url>
@ -1198,6 +1116,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
self.stopped[msg.args[0]] = False
if 'delay' in optlist:
@ -1214,8 +1135,8 @@ class ASCII(callbacks.Plugin):
else:
irc.reply("Invalid file type.", private=False, notice=False)
return
file = file.content.decode()
for line in file.splitlines():
file = file.content.decode().replace('\r\n','\n')
for line in file.split('\n'):
if line.strip() and not self.stopped[msg.args[0]]:
time.sleep(delay)
irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
@ -1227,6 +1148,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
opts = ''
if 'l' in optlist:
@ -1238,7 +1162,7 @@ class ASCII(callbacks.Plugin):
if 'n' in optlist:
opts += '-n '.format(n)
if 'p' in optlist:
opts += '-p '.format(p)
opts += '-p '
if 't' in optlist:
t = optlist.get('t')
opts += '-t {0} '.format(t)
@ -1260,7 +1184,7 @@ class ASCII(callbacks.Plugin):
filepath = "{0}/tmp".format(path)
filename = "{0}/{1}".format(filepath, url.split('/')[-1])
r = requests.get(url, headers=header)
open(filename, 'wb').write(r.content)
open(filename, 'wb').write(r.content.replace(b';5;', b';'))
try:
output = pexpect.run('a2m {0} {1}'.format(opts.strip(), str(filename)))
try:
@ -1278,16 +1202,21 @@ class ASCII(callbacks.Plugin):
return
paste = ""
self.stopped[msg.args[0]] = False
output = re.sub('(\x03(\d+).*)\x03,', '\g<1>\x03\g<2>,', output.decode())
for line in output.splitlines():
line = line.decode()
if self.registryValue('pasteEnable', msg.args[0]):
paste += line + "\n"
if line.strip() and not self.stopped[msg.args[0]]:
time.sleep(delay)
irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
elif not line.strip() and not self.stopped[msg.args[0]]:
time.sleep(delay)
irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
else:
return
if self.registryValue('pasteEnable', msg.args[0]):
irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
a2m = wrap(a2m, [optional('channel'), getopts({'l':'int', 'r':'int', 't':'int', 'w':'int', 'delay':'float'}), ('text')])
a2m = wrap(a2m, [optional('channel'), getopts({'l':'int', 'r':'int', 't':'int', 'w':'int', 'p':'', 'delay':'float'}), ('text')])
def p2u(self, irc, msg, args, channel, optlist, url):
"""[<channel>] [--b] [--f] [--p] [--s] [--t] [--w] [--delay] <url>
@ -1295,6 +1224,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
opts = ''
if 'b' in optlist:
@ -1378,6 +1310,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
opts = ''
if 'f' in optlist:
@ -1433,6 +1368,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
opts = ''
if 'f' in optlist:
@ -1521,6 +1459,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
if 'delay' in optlist:
delay = optlist.get('delay')
@ -1540,7 +1481,6 @@ class ASCII(callbacks.Plugin):
speed = 'fast'
file = requests.get("http://wttr.in/{0}".format(location))
output = file.content.decode()
self.matches = {}
output = self.ansi2irc(output)
output = re.sub('', '', output)
output = re.sub('', ' ', output)
@ -1571,6 +1511,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
if 'delay' in optlist:
delay = optlist.get('delay')
@ -1594,7 +1537,6 @@ class ASCII(callbacks.Plugin):
sub = 'usd'
if not coin:
coin = ''
self.matches= {}
file = requests.get("http://{0}.rate.sx/{1}".format(sub, coin))
output = file.content.decode()
output = self.ansi2irc(output)
@ -1623,6 +1565,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
if 'delay' in optlist:
delay = optlist.get('delay')
@ -1654,6 +1599,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
if 'delay' in optlist:
delay = optlist.get('delay')
@ -1678,6 +1626,9 @@ class ASCII(callbacks.Plugin):
"""
if not channel:
channel = msg.args[0]
if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
irc.errorNoCapability('admin')
return
optlist = dict(optlist)
if 'delay' in optlist:
delay = optlist.get('delay')