ascii.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. '''
  2. ASCII Art maker
  3. Creates an ascii art image from an arbitrary image
  4. Created on 7 Sep 2009
  5. @author: Steven Kay
  6. '''
  7. from PIL import Image
  8. import random
  9. from bisect import bisect
  10. import urllib
  11. import datetime
  12. import string
  13. import os
  14. # greyscale.. the following strings represent
  15. # 7 tonal ranges, from lighter to darker.
  16. # for a given pixel tonal level, choose a character
  17. # at random from that range.
  18. greyscale = [
  19. " ",
  20. " ",
  21. ".,-",
  22. "_ivc=!/|\\~",
  23. "gjez]/(YL)t[+TVf",
  24. "mdKZGbNDXYP*Q",
  25. "WKMA",
  26. "#%$"
  27. ]
  28. irccolors = [
  29. (204, 204, 204),
  30. (0, 0, 0),
  31. (54, 54, 178),
  32. (42, 140, 42),
  33. (195, 59, 59),
  34. (199, 50, 50),
  35. (128, 37, 127),
  36. (102, 54, 31),
  37. (217, 166, 65),
  38. (61, 204, 61),
  39. (26, 85, 85),
  40. (47, 140, 116),
  41. (69, 69, 230),
  42. (176, 55, 176),
  43. (76, 76, 76),
  44. (149, 149, 149)
  45. ]
  46. # using the bisect class to put luminosity values
  47. # in various ranges.
  48. # these are the luminosity cut-off points for each
  49. # of the 7 tonal levels. At the moment, these are 7 bands
  50. # of even width, but they could be changed to boost
  51. # contrast or change gamma, for example.
  52. zonebounds=[36,72,108,144,180,216,252]
  53. # open image and resize
  54. # experiment with aspect ratios according to font
  55. def colorDistance(c1, c2):
  56. return abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2])
  57. def sanitize(filename):
  58. valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
  59. return ''.join(c for c in filename if c in valid_chars)
  60. def rainbow():
  61. s = ""
  62. for x in range(0, 16):
  63. s += setcolor(0, x)
  64. s += " "
  65. s += clearcolor()
  66. return s
  67. def setcolor(fg, bg):
  68. return "\x03" + str(fg) + "," + str(bg)
  69. def clearcolor():
  70. return "\x03"
  71. def getlum(pixel):
  72. return 255 - int((pixel[0] + pixel[1] + pixel[2]) * 1.0 / 3)
  73. def findcolor(pixel):
  74. global irccolors
  75. mindistance = 10000
  76. bestcol = None
  77. for x in range(0, len(irccolors)):
  78. col = irccolors[x]
  79. distance = colorDistance(col, pixel)
  80. if distance < mindistance:
  81. mindistance = distance
  82. bestcol = x
  83. if getlum(pixel) > getlum(col):
  84. return setcolor(1, bestcol)
  85. else:
  86. return setcolor(0, bestcol)
  87. return ""
  88. def asciify(url):
  89. print "asciifying..."
  90. downloader = urllib.URLopener()
  91. time = str(datetime.datetime.now())
  92. filename = sanitize(time + url)
  93. path = "./" + filename
  94. print "path: " + path
  95. downloader.retrieve(url, path)
  96. print "downloaded"
  97. im=Image.open(path)
  98. print "opened"
  99. ratio = im.size[0] * 2.4 / im.size[1]
  100. width = int(ratio * 10)
  101. im = im.resize((width, 10), Image.BILINEAR)
  102. #im = im.convert("L") # convert to mono
  103. # now, work our way over the pixels
  104. # build up str
  105. arr = []
  106. line = "+"
  107. for x in range(0,im.size[0]):
  108. line = line + "-"
  109. line = line + "+"
  110. arr.append(line)
  111. for y in range(0,im.size[1]):
  112. line = "|"
  113. for x in range(0,im.size[0]):
  114. pixel = im.getpixel((x,y))
  115. lum = getlum(pixel)
  116. row = bisect(zonebounds,lum)
  117. possibles = greyscale[row]
  118. line = line + findcolor(pixel)
  119. line = line + possibles[random.randint(0, len(possibles) - 1)]
  120. line = line + clearcolor()
  121. line = line + "|"
  122. arr.append(line)
  123. line = "+"
  124. for x in range(0,im.size[0]):
  125. line = line + "-"
  126. line = line + "+"
  127. arr.append(line)
  128. os.remove(path)
  129. return arr