homepage/tartans/loom.py

205 lines
5.3 KiB
Python
Executable File

#! /usr/bin/python
# coding: utf-8
import re
import random
class Yarn:
"""A spool of yarn.
Color is specified as a 3-tuple (red, green, blue) of
saturation values ranging from 0.0 (no saturation) to
1.0 (full saturation).
Since we're pretending to be actual dyes here, we can fuzz it out a
bit by not doing full screen saturation and adding a little bit of
randomness to the color when queried.
"""
maxval = 190
fuzz = 0
def __init__(self, r, g, b):
self.rgb = (r, g, b)
self.intrgb = [int(c * self.maxval) for c in self.rgb]
intfuzz = int(self.fuzz * self.maxval)
self.limits = [(max(0, c - intfuzz), min(self.maxval, c + intfuzz))
for c in self.intrgb]
def __repr__(self):
return '<Yarn %r>' % (self.rgb)
def get_color(self):
if self.fuzz:
color = [random.randrange(l, h) for (l, h) in self.limits]
return color
else:
return self.intrgb
class Loom:
def __init__(self, warp):
self.warp = warp
self.fabric = []
def weave(self, yarn, up=1, down=1, skip=0, repeat=0):
offset = (len(self.fabric) / (repeat + 1)) * (skip + 1)
harnesses = up + down
row = []
for i in range(len(self.warp)):
j = (i + offset) % harnesses
if j < down:
row.append(self.warp[i])
else:
row.append(yarn)
self.fabric.append(row)
def plain_weave(self, yarn):
# AKA tabby weave, taffeta weave
self.weave(yarn)
def twill(self, yarn, up=2, down=2):
self.weave(yarn, up, down)
def satin_weave(self, yarn):
# 1/16, skip 4
self.weave(yarn, 1, 16, 4)
def basket_weave(self, yarn):
# 2/2, skip 1, repeat 1
self.weave(yarn, 2, 2, 1, 1)
class PNGLoom(Loom):
def png(self, outf, scale=1):
import Image
import array
imgstr = array.array('B')
for fr in self.fabric:
row = []
for c in fr:
for i in range(scale):
row.extend(c.get_color())
for i in range(scale):
imgstr.fromlist(row)
x = len(fr * scale)
y = len(self.fabric * scale)
img = Image.fromstring('RGB', (x, y), imgstr.tostring())
img.save(outf, 'PNG')
def ascii_test():
print('Plain weave')
l = Loom('||||||||||||||||||||||||||||||||')
for i in range(16):
l.plain_weave('-')
for row in l.fabric:
print(' ', ''.join(row))
print('Twill')
l = Loom('||||||||||||||||||||||||||||||||')
for i in range(16):
l.twill('-')
for row in l.fabric:
print(' ', ''.join(row))
print('2/1 twill')
l = Loom('||||||||||||||||||||||||||||||||')
for i in range(16):
l.twill('-', 2, 1)
for row in l.fabric:
print(' ', ''.join(row))
print('Satin weave')
l = Loom('||||||||||||||||||||||||||||||||')
for i in range(16):
l.satin_weave('-')
for row in l.fabric:
print(' ', ''.join(row))
print('Basketweave')
l = Loom('||||||||||||||||||||||||||||||||')
for i in range(16):
l.basket_weave('-')
for row in l.fabric:
print(' ', ''.join(row))
##
## Tartan junk
##
#
# Colors according to http://www.tartanregister.gov.uk/guidance.aspx
#
colors = {'R': Yarn(0.50, 0.00, 0.00), # Red
'G': Yarn(0.00, 0.40, 0.00), # Green
'B': Yarn(0.00, 0.00, 0.50), # Blue
'C': Yarn(0.00, 0.50, 0.50), # Cyan
'Y': Yarn(0.80, 0.80, 0.00), # Yellow
'P': Yarn(0.60, 0.00, 0.60), # Purple
'W': Yarn(0.90, 0.90, 0.90), # White
'K': Yarn(0.00, 0.00, 0.00), # Black
'BK': Yarn(0.00, 0.00, 0.00), # Black
'GR': Yarn(0.50, 0.50, 0.50), # Gray
'DB': Yarn(0.00, 0.00, 0.30), # Dark Blue
'LB': Yarn(0.00, 0.40, 0.90), # Light Blue
'LR': Yarn(0.80, 0.00, 0.00), # Light Red
'LG': Yarn(0.00, 0.60, 0.00), # Light Green
'LV': Yarn(0.50, 0.25, 0.60), # Lavender
'BR': Yarn(0.60, 0.40, 0.20), # Brown
'LGR': Yarn(0.60, 0.60, 0.60), # Light Gray
'LBR': Yarn(0.80, 0.70, 0.50), # Light Brown
}
sett_re = re.compile('([A-Za-z]{1,3}|\([A-Fa-f0-9]{3}\))(\d{1,3})')
def str_to_sett(s):
"""Convert an xtartan sett string into a sett tuple."""
sett = []
while s:
m = sett_re.search(s)
if not m:
break
cs = m.group(1)
if cs[0] == '(' and cs[-1] == ')':
ca = []
for a in cs[1:-1]:
ca.append(int(a+a, 16) / 256.0)
y = Yarn(*ca)
else:
y = colors[cs]
for i in range(int(m.group(2))):
sett.append(y)
s = s[m.end():]
if not s.endswith('.'):
o = sett[:]
o.reverse()
sett += o
if len(sett) % 4:
sett += sett
return sett
def tartan(sett):
l = PNGLoom(sett)
for y in sett:
l.twill(y)
return l
if __name__ == '__main__':
import sys
for line in sys.stdin:
if line.startswith('Sett:'):
_, s = line.split(':', 1)
s = s.strip()
break
sett = str_to_sett(s)
l = tartan(sett)
l.png(sys.stdout, 1)