-
Notifications
You must be signed in to change notification settings - Fork 2
/
markovio.py
executable file
·119 lines (90 loc) · 2.97 KB
/
markovio.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python
import subprocess, sys, re, random, getopt
usage = """\
usage: %s [options] [inputfile]
options:
-h, --help: this help.
-b x, --bg-pixel=x: background pixel character of x. default is space.
-s x, --output-scale=x: how large to magnify output png. default is 8.
input file defaults to "./input.xpm". it must be an xpm in a similar format to
the ones made by the gimp.""" % sys.argv[0]
try:
opts, args = getopt.getopt(sys.argv[1:], "hb:s:", ["help", "bg-pixel=", "output-scale="])
except getopt.GetoptError, e:
print str(e)
print
print usage
sys.exit(2)
bgpixel = ' '
outputscale = 8
infile = open(args[0] if args else 'input.xpm')
for o, a in opts:
if o in ('-b', '--bg-pixel'):
assert len(a) == 1
bgpixel = a
elif o in ('-s', '--output-scale'):
outputscale = int(a)
elif o in ('-h', '--help'):
print usage
sys.exit(0)
def raw_line_data(line):
return line.lstrip('"').rstrip('"},;\n')
lines = [ line for line in infile.readlines() if line.strip() ]
width = len(raw_line_data(lines[-1]))
imglines = [ raw_line_data(line) for line in lines if len(line) > width ]
height = len(imglines)
header = lines[:-height]
# reversed because building from bottom to top and right to left works better
imglines = imglines[::-1]
def adjacent(data, x, y):
above = data[y-1][x ] if 0 < y < height-1 else None
left = data[y ][x-1] if 0 < x else None
leftleft = data[y ][x-2] if 1 < x else None
aboveleft = data[y-1][x-1] if above and left else None
return above, left, leftleft, aboveleft
# build markov chains
table = {}
for y, line in enumerate(imglines):
for x, pixel in enumerate(line):
key = (y,) + adjacent(imglines, x, y)
table.setdefault(key, []).append(pixel)
# generate output
output = []
for y in range(height):
output.append([])
for x in range(width):
key = (y,) + adjacent(output, x, y)
output[-1].append(random.choice(table.get(key, bgpixel)))
# un-reverse only vertically -- but leave horizontal alone. why does this work
# best? who the hell knows?
output = output[::-1]
# write
prefix = '/tmp/markovio.out'
xpm = prefix+'.xpm'
png = prefix+'.png'
f = open(xpm, 'w')
f.write(''.join(header))
for y in range(height):
f.write('"')
for x in range(width):
f.write(output[y][x])
f.write('"')
if y < height-1:
f.write(',\n')
else:
f.write('};')
f.close()
print open(xpm, 'r').read()
print
sys.stdout.write("the above xpm image was written to %s" % xpm)
try:
subprocess.Popen([
"convert", '-scale',
"%dx%d" % (width*outputscale, height*outputscale),
xpm, png
]).wait()
except OSError:
print ",\nalthough conversion from xpm to png didn't work."
print "do you have the 'convert' utility installed (from imagemagick)?"
else:
print " and\nalso converted to %s, scaled up %d times" % (png, outputscale)