Modigliani (ASCII Art and IRC) 04-20-2014, 10:36 PM
#1
Hello
OK, Modigliani (Amedeo Clemente Modigliani 1884 – 1920) was a great Italian painter, so what does this has to do with Python and HC/You?
Today I will the code of my very personal IRC bot... it does only one thing: it takes a link of an image (any image online) and convert it into ASCII Art then send it to the user in a private message, nothing more... nothing less!
I talked about IRC clients in a previous thread "IRC Clients for Beginners", and now I will only discuss my code, so this is not a tutorial, it is one project of a group of projects I am working on for the community, more information read "Open projects (Workshop)", so let's get started.
You can find this bot sometimes online (in our channel irc.freenode.net: #hackcommunity.com), I will host it for the moment (you can download the code and host your own)... anyway!
So as I mentioned before, we need to:
Connect to IRC Channel
I will be using a socket to connect to irc.freenode.net (where our channel is, then I will send the following commands:
So here is our basic code:
Respond to PING Requests
Now we have to respond to PING requests with PONG in order to stay alive, this is easy to do, after the last line of code above we add:
The PING request looks something like this:
"sendak" can be anything else... means thaat it is not static...
Our response should look like this:
So to get the "
endak.freenode.net" part we will split the buffer (using space), in this case buffer[0] = 'PING' and buffer[1] = '
endak.freenode.net'
We can also add another line to force the bot to quit once a '!q' is passed:
Scan for Links
The command to scan a link is:
Where <link> is the address of the link (The URL), the bot will receive this message in this format (raw data):
So to extract user name and URL we'll need two regex:
I am not an expert in Python, so please if you can help me here that would be cool! (I am not a programmer after all)
I think the code is clear enough... basic regex operations to get the user name and the URl...
Download the Image
I will use urllib to download the image which is not the best solution... use mechanize instead! (I will not change the original code)
Details:
cStringIO.StringIO() will read a string buffer
urllib.urlopen() will open and download a document from the web, we pass the URL of that source ad done!
The .read() part will actually read that file and return back it's contents.
Image.open() will open an image file (see later the full code)
Convert an Image to ASCII ART
This is the fun part! How does it work?
By the way, thanks to Stevendkay for all the tips and help to finish this part! If you have any questions please don't hesitate to ask! (or PM me)
Viewing Result in IRC
We have some issues to face here:
So
Testing and Conclusion
!paint http://1.bp.blogspot.com/-DPMXGptMqAg/UC...Snoopy.jpg
Original:
![[Image: How+To+Draw+Snoopy.jpg]](http://1.bp.blogspot.com/-DPMXGptMqAg/UCxtIo2AQvI/AAAAAAAACcU/hIgqNQd6UHw/s1600/How+To+Draw+Snoopy.jpg)
Result:
![[Image: tsbOpaj.png]](http://i.imgur.com/tsbOpaj.png)
For me personally it was fun more than anything else, although I know that this is not a perfect Image/ASCII converter, but it is a start! Some images will not be as clear as others, so you have to test! And please, if you find something cool post a snapshot of the output in the comments, I recommend that you copy/paste the output in a notepad (I use leafpad) so that it has a white background (better effect)...
If you want to help this project please do... I know that the code is not as good as it should be!
This project took me couple of hours to finish.
-----------------------------------------------------------------
Issues
OK, Modigliani (Amedeo Clemente Modigliani 1884 – 1920) was a great Italian painter, so what does this has to do with Python and HC/You?

Today I will the code of my very personal IRC bot... it does only one thing: it takes a link of an image (any image online) and convert it into ASCII Art then send it to the user in a private message, nothing more... nothing less!
I talked about IRC clients in a previous thread "IRC Clients for Beginners", and now I will only discuss my code, so this is not a tutorial, it is one project of a group of projects I am working on for the community, more information read "Open projects (Workshop)", so let's get started.
You can find this bot sometimes online (in our channel irc.freenode.net: #hackcommunity.com), I will host it for the moment (you can download the code and host your own)... anyway!
So as I mentioned before, we need to:
- Connect to the channel.
- Respond to PING requests (with PONG).
- Scan for Links.
- Get the image (download).
- Convert the downloaded image to ASCII.
- Post the ASCII result in a private message to the user.
Connect to IRC Channel
I will be using a socket to connect to irc.freenode.net (where our channel is, then I will send the following commands:
- Change the nick name.
- Sign in (user).
- Join the channel.
- Send a hello message.
So here is our basic code:
Code:
import socket
network = 'irc.freenode.net'
channel = 'hackcommunity.com'
port = 6667
if __name__ == '__main__':
mySock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
mySock.connect((network, port))
mySock.send ('NICK Modigliani\r\n')
mySock.send ('USER Modilgiani HCASCII HCART :Python IRC\r\n')
mySock.send ('JOIN #%s\r\n'% channel)
mySock.send ('PRIVMSG #%s :Hello!\r\n' % channel)
while True:
buffer = mySock.recv(4096)Respond to PING Requests
Now we have to respond to PING requests with PONG in order to stay alive, this is easy to do, after the last line of code above we add:
Code:
if buffer.find ( 'PING' ) != -1:
mySock.send ( 'PONG ' + buffer.split() [ 1 ] + '\r\n' )The PING request looks something like this:
Code:
PING :sendak.freenode.net"sendak" can be anything else... means thaat it is not static...
Our response should look like this:
Code:
PONG :sendak.freenode.netSo to get the "
endak.freenode.net" part we will split the buffer (using space), in this case buffer[0] = 'PING' and buffer[1] = '
endak.freenode.net'We can also add another line to force the bot to quit once a '!q' is passed:
Code:
if buffer.find ( '!q' ) != -1:
mySock.send ( "PRIVMSG #" + channel + " :Goodbye!\r\n" )
mySock.send ( 'QUIT\r\n' )
mySock.close()
breakScan for Links
The command to scan a link is:
Code:
!paint <link>Code:
:ligeti!~ligeti@unaffiliated/ligeti PRIVMSG #hackcommunity.com :!paint http://uploads3.wikipaintings.org/images/amedeo-modigliani/portrait-of-a-woman-1919.jpgSo to extract user name and URL we'll need two regex:
- For user: ^
.+?)!
- For URL: \s:!paint\s*(.+?)$
I am not an expert in Python, so please if you can help me here that would be cool! (I am not a programmer after all)
Code:
import re
## ############################## ##
if buffer.find( '!paint' ) != -1:
regex = '^:(.+?)!'
pattern = re.compile(regex)
usr = re.findall(pattern, buffer)
regex = '\s:!paint\s*(.+?)$'
pattern = re.compile(regex)
url = re.findall(pattern, buffer)
print usr, urlI think the code is clear enough... basic regex operations to get the user name and the URl...
Download the Image
I will use urllib to download the image which is not the best solution... use mechanize instead! (I will not change the original code)
Code:
import cStringIO
import urllib
from PIL import Image
imgfile = cStringIO.StringIO(urllib.urlopen(str(url[0])).read())
im = Image.open(imgfile)Details:
cStringIO.StringIO() will read a string buffer
urllib.urlopen() will open and download a document from the web, we pass the URL of that source ad done!
The .read() part will actually read that file and return back it's contents.
Image.open() will open an image file (see later the full code)
Convert an Image to ASCII ART
This is the fun part! How does it work?
- We scale the image.
- We convert it to mono
- We convert it to ASCII
Code:
import sys
import random
from bisect import bisect
## ############################## ##
scale = "$@B%&WM#ZQL*oahkbdpqwmCUYXzcvunxrft/\|()1{}[]?-_+~<>!lI;:,\"^`'. "
scale= scale[::-1]
zonebounds=range(4,256,4)
try:
imgfile = cStringIO.StringIO(urllib.urlopen(str(url[0])).read())
im = Image.open(imgfile)
height = (im.size[1] * 80) / (im.size[0])
im = im.resize((100, height), Image.ANTIALIAS)
im = im.convert('L')
imgBuf=""
for y in range(0,im.size[1]):
imgBuf = ""
for x in range(0,im.size[0]):
lum = 255-im.getpixel((x,y))
row = bisect(zonebounds,lum)
possibles = scale[row]
imgBuf =imgBuf+possibles[random.randint(0,len(possibles)-1)]
print str(imgBuf) + '\n'
except:
e = sys.exc_info()
print str(e)By the way, thanks to Stevendkay for all the tips and help to finish this part! If you have any questions please don't hesitate to ask! (or PM me)
Viewing Result in IRC
We have some issues to face here:
- We shouldn't Spam any channel so we will post the result in a private conversation.
- It will be time consuming as each row of pixels will be followed with 1 second of delay so the IRC server will not think that the bot will Spam the channel.
So
Code:
import time
## ############################## ##
mySock.send ('PRIVMSG ' + str(usr[0]) + ' :' + imgBuf + '\r\n')
time.sleep(1)Testing and Conclusion
!paint http://1.bp.blogspot.com/-DPMXGptMqAg/UC...Snoopy.jpg
Original:
![[Image: How+To+Draw+Snoopy.jpg]](http://1.bp.blogspot.com/-DPMXGptMqAg/UCxtIo2AQvI/AAAAAAAACcU/hIgqNQd6UHw/s1600/How+To+Draw+Snoopy.jpg)
Result:
![[Image: tsbOpaj.png]](http://i.imgur.com/tsbOpaj.png)
For me personally it was fun more than anything else, although I know that this is not a perfect Image/ASCII converter, but it is a start! Some images will not be as clear as others, so you have to test! And please, if you find something cool post a snapshot of the output in the comments, I recommend that you copy/paste the output in a notepad (I use leafpad) so that it has a white background (better effect)...
If you want to help this project please do... I know that the code is not as good as it should be!
This project took me couple of hours to finish.
Spoiler: Complete code:
Code:
import socket
import re
import cStringIO
import urllib
import sys
import random
import time
from bisect import bisect
from PIL import Image
network = 'irc.freenode.net'
channel = '#hackcommunity.com'
port = 6667
scale = "$@B%&WM#ZQL*oahkbdpqwmCUYXzcvunxrft/\|()1{}[]?-_+~<>!lI;:,\"^`'. "
scale= scale[::-1]
zonebounds=range(4,256,4)
if __name__ == '__main__':
mySock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
mySock.connect((network, port))
mySock.send ('NICK Modigliani\r\n')
mySock.send ('USER Modilgiani HCASCII HCART :Python IRC\r\n')
mySock.send ('JOIN #%s\r\n'% channel)
mySock.send ('PRIVMSG #%s :Hello!\r\n' % channel)
while True:
buffer = mySock.recv(4096)
if buffer.find ( 'PING' ) != -1:
mySock.send ( 'PONG ' + buffer.split() [ 1 ] + '\r\n' )
if buffer.find ( '!q' ) != -1:
mySock.send ( "PRIVMSG #" + channel + " :Goodbye!\r\n" )
mySock.send ( 'QUIT\r\n' )
mySock.close()
break
if buffer.find( '!paint' ) != -1:
regex = '^:(.+?)!'
pattern = re.compile(regex)
usr = re.findall(pattern, buffer)
regex = '\s:!paint\s*(.+?)$'
pattern = re.compile(regex)
url = re.findall(pattern, buffer)
print usr, url
try:
imgfile = cStringIO.StringIO(urllib.urlopen(str(url[0])).read())
im = Image.open(imgfile)
height = (im.size[1] * 80) / (im.size[0])
im = im.resize((100, height), Image.ANTIALIAS)
im = im.convert('L')
imgBuf=""
for y in range(0,im.size[1]):
imgBuf = ""
for x in range(0,im.size[0]):
lum=255-im.getpixel((x,y))
row=bisect(zonebounds,lum)
possibles=scale[row]
imgBuf=imgBuf+possibles[random.randint(0,len(possibles)-1)]
mySock.send ('PRIVMSG ' + str(usr[0]) + ' :' + imgBuf + '\r\n')
time.sleep(1)
print str(imgBuf) + '\n'
except:
e = sys.exc_info()
print str(e)
print buffer-----------------------------------------------------------------
Issues
- Error: "Modigliani has quit (Read error: Connection reset by peer)"
![[Image: wvBFmA5.png]](http://i.imgur.com/wvBFmA5.png)


![[+]](https://sinister.li/images/modern/collapse_collapsed.png)