Do you remeber the "old" internet? before webbrowsers, when everything had a strong unix flavour? Back then there was something called "ascii art" that is, use the ascii letters to create an image. Here is a program that takes an image (640x384) and converts it to ascii strings. I wanted to create this image for a t-shirt
You would need to copy the "courier new" font from your font directory to the same directory as the script, and also add an image that should be converted: -
import Image, ImageDraw
-
import ImageFont
-
import math
-
-
# funny useless program
-
-
lu = []
-
for i in range(125-32):
-
lu.append(chr(i+33))
-
i2 = Image.new("RGBA",(64,64))
-
ii = Image.open("mona.png") # change this to your own picture, but it needs to be 640x384!
-
im = Image.new("RGBA",(64,64))
-
d = ImageDraw.Draw(im)
-
f = ImageFont.truetype("courbi.ttf",13)
-
-
str=""
-
for v in range(24):
-
print v
-
for k in range(80):
-
chr = ""
-
maxdiff = 0xffffff
-
for e in lu:
-
d.rectangle([0,0,64,64], fill=0)
-
d.text((0,0),e,font=f,fill=0xffffff)
-
diff = 0
-
r0 = 0
-
g0 = 0
-
b0 = 0
-
for a in range(16):
-
for b in range(8):
-
c = im.getpixel((b,a))[0]
-
c0 = (ii.getpixel((b+(k*8),a+(v*16)))[0] + ii.getpixel((b+(k*8),a+(v*16)))[1] + ii.getpixel((b+(k*8),a+(v*16)))[2])/3.0
-
r0+= ii.getpixel((b+(k*8),a+(v*16)))[0]
-
g0+= ii.getpixel((b+(k*8),a+(v*16)))[1]
-
b0+= ii.getpixel((b+(k*8),a+(v*16)))[2]
-
-
diff+=abs(c-c0)
-
if(diff < maxdiff):
-
maxdiff = diff
-
chr = e
-
-
r0*=1.0
-
g0*=1.0
-
b0*=1.0
-
r0/=(16.0*8.0)
-
g0/=(16.0*8.0)
-
b0/=(16.0*8.0)
-
ir0 = int(r0)
-
ig0 = int(g0)
-
ib0 = int(b0)
-
-
r1 = hex(ir0)
-
r1 = r1[2:len(r1)]
-
g1 = hex(ig0)
-
g1 = g1[2:len(g1)]
-
b1 = hex(ib0)
-
b1 = b1[2:len(g1)]
-
-
if(chr == " "):
-
chr=" "
-
-
str+="<td width=\"8px\"><font size=\"1px\" color=\"#"+r1+g1+b1+"\">"+chr+"</font></td>"
-
str="<tr>"+str+"</tr>"
-
-
str= "<html><body bgcolor=\"#000000\"><table width=\"640px\" height=\"386px\">"+str+"</table></body></html>"
-
f = open("mona.txt","w")
-
f.write(str)
-
f.close()
-
This program output it as a .html file, but it should easy to modify so it will output txt instead.
-kudos
1 6880
I have modified your code to do a few things different.
It speeds it up enormously. I took 6min down to 1sec. I also made it run based on commandline parser so you can now put this on your website or wherever you want. There are a few issues in it if I recall (its been about 6 months since I wrote this). Feel free to tune it up and bring it back for everyone to have. It also uses true luminance vals in algorithm (if wanted).
-------------------------------------- - '''
-
Inspired by -Kudos code from http://bytes.com/topic/python/insights/874180-ascii-art-creator
-
Pretty much a rewrite, but I give kudos complete props for posting this and making it fun and easy
-
'''
-
-
-
import sys,os
-
import Image, ImageDraw
-
import ImageFont
-
import math
-
import time, random
-
from optparse import OptionParser
-
-
-
# funny useless program
-
t0 = time.time();
-
VERBOSE_LEVEL = 1;
-
MIN_LUM_DEFAULT = .1;
-
MAX_LUM_DEFAULT = 1.0;
-
OFFSET_LUM_DEFAULT = 0;
-
OUTPUT_FONT_SIZE_DEFAULT = 3;
-
CHARMAP_DEFAULT = 'luminance';
-
-
ROWS_DEFAULT = 24
-
COLS_DEFAULT = 80
-
-
MAX_RGB = 255
-
MAX_F_RGB = float(MAX_RGB)
-
-
def normalizePixel( rgb ):
-
return rgb[0]/MAX_F_RGB,rgb[1]/MAX_F_RGB,rgb[2]/MAX_F_RGB
-
-
def getLuminancePixel( rgb ):
-
nR,nG,nB = normalizePixel( rgb )
-
return nR*0.299 + nG*0.587 + nB*0.114
-
-
def output( val, vLevel=0 ):
-
if vLevel <= VERBOSE_LEVEL:
-
print ( val )
-
-
def main( args ):
-
-
global VERBOSE_LEVEL;
-
-
parser = OptionParser()
-
parser.add_option("-f", "--file", action='append', dest="files", help="process these files", metavar="LIST")
-
parser.add_option( "--characters", action="store", dest="characters", help="characters to use")
-
parser.add_option( "--character_map", action="store", dest="characterMap", help="maps characters: luminance, order, random")
-
parser.add_option("-r", "--rows", action="store", dest="rows", help="number of rows")
-
parser.add_option("-c", "--columns", action="store", dest="columns", help="number of columns")
-
parser.add_option( "--min_luminance", action="store", dest="minLuminance", help="min luminance value to clip at black")
-
parser.add_option( "--max_luminance", action="store", dest="maxLuminance", help="max luminance value to clip at white")
-
parser.add_option( "--offset_luminance", action="store", dest="offsetLuminance", help="offset luminance value")
-
parser.add_option( "--output_font_size", action="store", dest="outputFontSize", help="output font size in px")
-
parser.add_option('-v', "--verbose", action="store", dest="verbose", help="verbosity: 0=None, 1=completion output, 2=image info, 3=pixel blending info")
-
-
(options, args) = parser.parse_args( args )
-
-
files = options.files;
-
characters = options.characters;
-
characterMap = options.characterMap;
-
rows = options.rows;
-
columns = options.columns;
-
minLum = options.minLuminance;
-
maxLum = options.maxLuminance;
-
offsetLum = options.offsetLuminance;
-
outputFontSize = options.outputFontSize;
-
verbose = options.verbose;
-
-
errors = [];
-
# SANITY CHECKS
-
-
if verbose:
-
try:
-
VERBOSE_LEVEL = int(verbose);
-
except:
-
VERBOSE_LEVEL = VERBOSE_LEVEL;
-
-
if not files:
-
errors.append('Failed to get files: make sure you specify files to use');
-
if not characters:
-
characters = []
-
for i in range( 125-32):
-
characters.append( chr( i + 33) );
-
else:
-
characters = str(characters);
-
-
if characterMap:
-
if characterMap.lower() in ('luminance','order','random'):
-
characterMap = characterMap.lower();
-
else:
-
characterMap = CHARMAP_DEFAULT;
-
else:
-
characterMap = CHARMAP_DEFAULT;
-
-
try:
-
rows = int(rows);
-
except:
-
rows = ROWS_DEFAULT;
-
try:
-
columns = int(columns);
-
except:
-
columns = COLS_DEFAULT;
-
-
try:
-
minLum = float( minLum)
-
except:
-
minLum = MIN_LUM_DEFAULT
-
try:
-
maxLum = float( maxLum)
-
except:
-
maxLum = MAX_LUM_DEFAULT
-
-
try:
-
offsetLum = int( offsetLum)
-
except:
-
offsetLum = OFFSET_LUM_DEFAULT
-
-
try:
-
outputFontSize = int( outputFontSize)
-
except:
-
outputFontSize = OUTPUT_FONT_SIZE_DEFAULT
-
-
if errors:
-
for err in errors:
-
output( 'ERROR: %s'%err, 0);
-
return -1;
-
-
output( 'verbose: %s'%verbose , 3 );
-
output( 'files: %s'%files , 3 );
-
output( 'characters: %s'%characters , 3 );
-
output( 'character_map: %s'%characterMap , 3 );
-
output( 'rows: %s'%rows , 3 );
-
output( 'columns: %s'%columns , 3 );
-
output( 'minLum: %s'%minLum , 3 );
-
output( 'maxLum: %s'%maxLum , 3 );
-
output( 'offsetLum: %s'%offsetLum , 3 );
-
output( 'outputFontSize: %s'%outputFontSize , 3 );
-
-
imgChr = Image.new("RGBA",(64,64))
-
drwObj = ImageDraw.Draw(imgChr)
-
fntObj = ImageFont.truetype("courbi.ttf",13)
-
-
-
# build the value table
-
lumLUT_Tmp = list();
-
lumLUT = list();
-
lumToCharTmp = dict();
-
maxLum = 0.0;
-
minLum = 1.0;
-
for ch in characters:
-
-
w,h = fntObj.getsize(ch)
-
drwObj.rectangle([0,0,64,64], fill=0)
-
drwObj.text((0,0),ch,font=fntObj,fill=0xffffff)
-
diff = 0
-
r0 = 0
-
g0 = 0
-
b0 = 0
-
-
lum = 0;
-
for a in range(16):
-
for b in range(8):
-
lum += getLuminancePixel( imgChr.getpixel((b,a)) )
-
lum = lum/(16*8)
-
lumLUT_Tmp.append( lum )
-
lumToCharTmp[lum] = ch ;
-
-
if lum > maxLum:
-
maxLum = lum;
-
if lum < minLum:
-
minLum = lum;
-
-
output( ('ch: %s\t(%sx%s) lum:%s'%(ch,w,h,lum)), 3);
-
lumToChar = dict();
-
for lum in lumLUT_Tmp:
-
nLum = (lum-minLum)/(maxLum-minLum);
-
lumToChar[nLum] = lumToCharTmp[lum];
-
lumLUT.append( nLum );
-
-
lumLUT.sort();
-
-
for file in files:
-
tImage = time.time()
-
imgSrc = Image.open(file)
-
iw,ih = imgSrc.size;
-
cellW = iw/columns;
-
cellH = ih/rows;
-
#~ print '\n%sx%s %sx%s'%(cellW,cellH, iw, ih)
-
sVal=""
-
index=0
-
for x in range(rows):
-
for y in range(columns):
-
ch = ""
-
maxdiff = 0xffffff
-
-
iLum = 0;
-
r = 0;
-
g = 0;
-
b = 0;
-
for xCell in range(cellH):
-
for yCell in range(cellW):
-
color = imgSrc.getpixel((yCell+(y*cellW),xCell+(x*cellH)));
-
r += color[0]
-
g += color[1]
-
b += color[2]
-
-
# average
-
r = r/(cellH*cellW*1.0);
-
g = g/(cellH*cellW*1.0);
-
b = b/(cellH*cellW*1.0);
-
-
hexColor = '%.2x%.2x%.2x'%( r+offsetLum,g+offsetLum,b+offsetLum );
-
-
# normalize
-
iLum += getLuminancePixel( (r,g,b) )
-
-
#~ r /= MAX_F_RGB;
-
#~ g /= MAX_F_RGB;
-
#~ b /= MAX_F_RGB;
-
-
if characterMap == 'luminance' :
-
ix = 0;
-
for lum in lumLUT:
-
if iLum < MIN_LUM_DEFAULT:
-
ch = ' ';
-
break;
-
if iLum > MAX_LUM_DEFAULT:
-
ch = lumToChar[lumLUT[-1]];
-
break;
-
if lum > iLum:
-
try:
-
ch = lumToChar[lumLUT[ix]];
-
except:
-
ch = lumToChar[lumLUT[0]]
-
break;
-
ix+=1;
-
-
elif characterMap == 'order':
-
if index >= len(characters):
-
index=0;
-
ch = characters[index];
-
elif characterMap == 'random':
-
ch = characters[int(random.random()*len(characters))];
-
-
index+=1
-
if(ch == " "):
-
ch=" "
-
#~ output( 'Character: %s'%ch, 3);
-
output( ('character: %s\trow:%s column:%s\tlum: %s\tr:%s g:%s b:%s\thex_color:%s'%(ch,x,y,iLum,r,g,b,hexColor)), 3);
-
sVal += '''<font size="%spx" color="#%s">%s</font></td>'''%(outputFontSize,hexColor,ch);
-
sVal += '<br/>';
-
sVal= "<html><body bgcolor=\"#000000\"><pre>"+sVal+"</pre><br/>\n<img src=\"%s\"/>\n</body></html>"%file
-
try:
-
f = open("%s.html"%file,"w")
-
f.write(sVal)
-
f.close()
-
except:
-
output('Failed to write file: %s'%file, 0 );
-
-
output( ('%s (%sx%s : %sx%s)'%(file,iw,ih,cellW,cellH)).center(50,'.'), 2)
-
output( 'IMAGE PROCESS TIME: %s (sec)\t%s'%((time.time()-tImage),os.path.basename(file)), 1);
-
-
output( '%s\nTOTAL PROCESS TIME: %s (sec)'%('-'*100, (time.time()-t0) ), 1);
-
-
if __name__=='__main__':
-
args = sys.argv;
-
-
args += [
-
#~ '--file','./angry_birds.jpg',
-
#~ '--characters','-+=@!?%$#^&*()[]{}_\\/><,.`~',
-
#~ '-r','80', '-c','260',
-
#~ '--output_font_size','1',
-
#~ '--character_map','random',
-
#~ '--character_map','order',
-
#~ '-v', '3',
-
-
]
-
-
sys.exit( main( args ) );
-
-
--------------------------------------
Sign in to post your reply or Sign up for a free account.
Similar topics
by: Stefan Ram |
last post by:
Some style guides suggest to repeat a DC.creator
meta-element for multiple authors, but doesn't this
contradict its specification?
"An entity primarily responsible for making
the content of the...
|
by: Gorilla |
last post by:
I bound my package with EXPLAIN(YES), and it's got the following static
SQL in it:
EXEC SQL SELECT CARDF, RECLENGTH
INTO :CARDF,:RECLENGTH
FROM SYSIBM.SYSTABLES
WHERE NAME = :TBNAME
AND...
|
by: Ger |
last post by:
I have not been able to find a simple, straight forward Unicode to ASCII
string conversion function in VB.Net.
Is that because such a function does not exists or do I overlook it?
I found...
|
by: shenanwei |
last post by:
I tried revoke all priviledge from user
and REVOKE DROPIN ON SCHEMA
Still the creator can drop the table.
|
by: Roshan |
last post by:
Hi,
I am trying to programatically add a FileSystemAccessRule for CREATOR
OWNER to the filesystemsecurity obj of a folder whose creator and owner
is a user account say 'SomeUser'. The rule gets...
|
by: anokun7 |
last post by:
We are using DB2 v7 on OS/390. I have installed db2connect enterprise
on my local windows XP box.
Using db2connect I have created a dsn and could successfully connect
using the DB2 control...
|
by: alive84 |
last post by:
Hi there,
I have a two problems concerning option button values on a report and data report creator reports.
The situation:
I have three option value boxes two have 3 option and one has...
|
by: alan |
last post by:
Hello all, I'd like to know if there is a nice method of defining a
functor creator which accepts an N-ary function and returns a functor
based on that function.
For example I have a function:...
|
by: phpFoxHelp |
last post by:
Hey everyone!
I am currently using phpFox to start an online community. I have it set so that there is no captcha nor email validation for new registrations. I am looking for a program that will...
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new...
| |