+
+I've written a [tartan designer](design) that will take a sett pattern
+in modified xtartan format, and output a PNG image of said tartan. Below
+are some tartans I've made with it.
+
+If you have one you'd like to contribute to my database, or would like
+the code that generates this stuff, feel free to [email
+me](mailto:neale-tartan@woozle.org).
diff --git a/tartans/loom.py b/tartans/loom.py
new file mode 100755
index 0000000..7e2cb61
--- /dev/null
+++ b/tartans/loom.py
@@ -0,0 +1,181 @@
+#! /usr/bin/python
+# coding: utf-8
+
+import re
+
+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).
+
+ """
+
+ def __init__(self, r, g, b):
+ self.rgb = (r, g, b)
+ self.color = (int(r * 256), int(g * 256), int(b * 256))
+
+ def __repr__(self):
+ return '' % (self.rgb)
+
+
+
+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.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 = {'R': Yarn(0.50, 0.00, 0.00), # Red
+ 'G': Yarn(0.00, 0.30, 0.00), # Green
+ 'B': Yarn(0.00, 0.00, 0.50), # Blue
+ 'C': Yarn(0.00, 0.25, 0.25), # Cyan
+ 'Y': Yarn(0.80, 0.80, 0.00), # Yellow
+ 'P': Yarn(0.60, 0.00, 0.60), # Purple (?!)
+ 'W': Yarn(0.60, 0.60, 0.60), # White
+ 'K': Yarn(0.00, 0.00, 0.00), # Black
+ 'BK': Yarn(0.00, 0.00, 0.00), # Black
+ 'GR': Yarn(0.25, 0.25, 0.25), # Gray
+ 'DB': Yarn(0.00, 0.00, 0.30), # Dark Blue
+ 'LB': Yarn(0.00, 0.25, 0.60), # Light Blue
+ 'LR': Yarn(0.60, 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.30, 0.25, 0.00), # Brown
+ 'LGR': Yarn(0.60, 0.60, 0.60), # Light Gray
+ 'LBR': Yarn(0.40, 0.40, 0.00), # 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
+ 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)
diff --git a/tartans/lstartans b/tartans/lstartans
new file mode 100755
index 0000000..324648b
--- /dev/null
+++ b/tartans/lstartans
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+for i in "$@"; do
+ base=$(basename $i .tartan)
+ name=$(awk -F': ' '(/^Name:/) {print $2; exit;}' $i)
+ echo "* [$name]($base.html)"
+done
diff --git a/tartans/nm.tartan b/tartans/nm.tartan
new file mode 100644
index 0000000..cb9e6ae
--- /dev/null
+++ b/tartans/nm.tartan
@@ -0,0 +1,10 @@
+Name: New Mexico
+Sett: R4 G24 B4 G16 B36 Y8 R4 Y4
+
+Designed by Ralph Stevenson Jr, [officially recognized in 2003](nm-proc)
+by the Secretary of State. It is similar in design to the [Albuquerque
+tartan](albuquerque). I bought a scarf of this plaid from
+Mr. Stevenson; it came with a photocopy of the tartan registration and a
+few other documents.
+
+[Bally Dun Celtic Treasures](http://www.ballydun.com/) sells this tartan.
diff --git a/tartans/nmloe.tartan b/tartans/nmloe.tartan
new file mode 100644
index 0000000..7246afb
--- /dev/null
+++ b/tartans/nmloe.tartan
@@ -0,0 +1,7 @@
+Name: New Mexico Land Of Enchantment
+Sett: LG8 LV32 R4 G32 LG32 Y4 LG4
+
+This isn't official but I think it's pretty. I just guessed at the
+sett pattern but I think I got pretty close.
+[Kathy Lare](http://www.kathyskilts.com/) is the sole source for this
+fabric.
diff --git a/tartans/nv.tartan b/tartans/nv.tartan
new file mode 100644
index 0000000..9aaf44e
--- /dev/null
+++ b/tartans/nv.tartan
@@ -0,0 +1,6 @@
+Name: Nevada
+Sett: W4 LGR16 B4 LGR8 B8 Y4 B4 R4 B20
+
+Based on a terrible gif that is apparently a part of [Nevada Revised
+Statute 235.130](http://leg.state.nv.us/NRS/NRS-235.html#NRS235Sec130).
+Designed by Richard Zygmunt Pawlowski, approved May 8, 2001.
diff --git a/tartans/ok.tartan b/tartans/ok.tartan
new file mode 100644
index 0000000..7c28ef6
--- /dev/null
+++ b/tartans/ok.tartan
@@ -0,0 +1,4 @@
+Name: Oklahoma
+Sett: R4 W8 LB64 Y6 BK16
+
+Based on a photo on a web page.
diff --git a/tartans/pjs.tartan b/tartans/pjs.tartan
new file mode 100644
index 0000000..07811c7
--- /dev/null
+++ b/tartans/pjs.tartan
@@ -0,0 +1,7 @@
+Name: Neale's PJs
+Sett: W7 C3 GR5 BK3 C5 BK3 C6 GR3 C5
+
+This is an approximation of the pajamas I was wearing when I wrote the
+tartan designer. They weren't actually a tartan. I guess modern
+weavers feel they ought to show off the fact that they can do fancy
+tricks with their looms.
diff --git a/tartans/pjs2.tartan b/tartans/pjs2.tartan
new file mode 100644
index 0000000..37e554e
--- /dev/null
+++ b/tartans/pjs2.tartan
@@ -0,0 +1,5 @@
+Name: Neale's PJs II
+Sett: W3 G24 Y2 W2 G2 W2 G2 W1
+
+More of my PJs. This one is an exact copy, I can count the threads
+in this fabric.
diff --git a/tartans/shrek.tartan b/tartans/shrek.tartan
new file mode 100644
index 0000000..beeaf20
--- /dev/null
+++ b/tartans/shrek.tartan
@@ -0,0 +1,6 @@
+Name: Shrek
+Sett: LBR4 BR8 G16 R2 G16 BR32
+
+I (Neale) created this based on Shrek's pants in a couple of frame grabs
+from the movie. It appears to be different from the recently-released
+"Shrek's Tartan".
diff --git a/tartans/tartan.m4 b/tartans/tartan.m4
new file mode 100644
index 0000000..bd0b411
--- /dev/null
+++ b/tartans/tartan.m4
@@ -0,0 +1,21 @@
+Title: TARTAN Tartan
+
+divert(1)
+
+
+
+I place this image in the public domain, in the hope that it will
+increase interest in tartans and tartan design.
+
+
+divert(0)
diff --git a/tartans/tartan.py b/tartans/tartan.py
new file mode 100755
index 0000000..d3bbf64
--- /dev/null
+++ b/tartans/tartan.py
@@ -0,0 +1,117 @@
+#! /usr/bin/python
+
+import sys
+import Image
+import re
+import array
+
+colors = {'R': '\x88\x00\x00', # Red
+ 'G': '\x00\x44\x00', # Green
+ 'B': '\x00\x00\x44', # Blue
+ 'C': '\x00\x44\x44', # Cyan
+ 'Y': '\x99\x99\x00', # Yellow
+ 'P': '\x99\x00\x99', # Purple (?!)
+ 'W': '\x99\x99\x99', # White
+ 'K': '\x00\x00\x00', # Black
+ 'BK': '\x00\x00\x00', # Black
+ 'GR': '\x44\x44\x44', # Gray
+ 'DB': '\x00\x00\x55', # Dark Blue
+ 'LB': '\x00\x44\x99', # Light Blue
+ 'LR': '\x99\x00\x00', # Light Red
+ 'LG': '\x00\x99\x00', # Light Green
+ 'LV': '\x88\x44\x99', # Lavender
+ 'BR': '\x55\x44\x00', # Brown
+ 'LGR': '\x99\x99\x99', # Light Gray
+ 'LBR': '\x66\x66\x00', # 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 = array.array('B')
+ for a in cs[1:-1]:
+ ca.append(int(a+a, 16))
+ c = ca.tostring()
+ else:
+ c = colors[cs]
+ n = int(m.group(2))
+ sett.append((c, n))
+ s = s[m.end():]
+ if not s.endswith('.'):
+ o = sett[:]
+ o.reverse()
+ sett += o
+ return sett
+
+
+
+class Loom:
+ """Simulates a simple loom with only one weft color per row.
+
+ This probably does a simplistic weave too, I don't know enough about
+ weaving to say for sure. But I can imagine more complicated ways of
+ doing it.
+
+ """
+
+ def __init__(self, warp):
+ self.warp = warp
+ self.cloth = []
+ self.row = 0
+
+ def weave(self, weft):
+ out = []
+ for i in range(len(self.warp)):
+ if (i + self.row) % 2 == 0:
+ out.append(weft)
+ else:
+ out.append(self.warp[i])
+
+ self.cloth.append(out)
+ self.row += 1
+
+
+class Tartan:
+ def __init__(self, sett):
+ # Weave a whole pattern suitable for tiling. In other words, it
+ # does the mirroring for you.
+
+ if type(sett) == type(''):
+ sett = str_to_sett(sett)
+
+ warp = []
+ for c,n in sett:
+ warp += [c]*n
+
+ if False:
+ # Offset it to the center of the first dealie
+ o = sett[0][1] / 2
+ warp += warp[:o]
+ del warp[:o]
+
+ self.loom = Loom(warp)
+ for w in warp:
+ self.loom.weave(w)
+
+ rgbs = [''.join(x) for x in self.loom.cloth]
+ imgstr = ''.join(rgbs)
+ self.img = Image.fromstring('RGB',
+ (len(self.loom.cloth[1]),
+ len(self.loom.cloth)),
+ imgstr)
+
+ def png(self, fd):
+ self.img.save(fd, 'PNG')
+
+if __name__ == '__main__':
+ sett = sys.argv[1]
+ t = Tartan(sett)
+ t.png(sys.stdout)
diff --git a/tartans/tartantomdwn b/tartans/tartantomdwn
new file mode 100755
index 0000000..0a4f88c
--- /dev/null
+++ b/tartans/tartantomdwn
@@ -0,0 +1,22 @@
+#! /bin/sh
+
+header () {
+ while IFS=: read key val; do
+ tval=$(echo $val | sed "s/'/\'/g")
+ case $key in
+ Name)
+ echo -n "TARTAN='$tval';"
+ ;;
+ Sett)
+ echo -n "SETT='$tval'"
+ ;;
+ "")
+ break
+ ;;
+ esac
+ done
+}
+
+eval $(header)
+m4 -DTARTAN="$TARTAN" -DSETT="$SETT" -DBASE="$1" tartan.m4 -
+
diff --git a/tartans/tx.tartan b/tartans/tx.tartan
new file mode 100644
index 0000000..4ac7243
--- /dev/null
+++ b/tartans/tx.tartan
@@ -0,0 +1,12 @@
+Name: Texas Bluebonnet
+Sett: G4 R2 B16 W2 R2 W2 LB16 W2 LB16 W2 Y1
+
+Based off a jpeg at the [Texas Scottish Heritage
+Society](http://www.txscot.com/BB_tartan.htm#bluebonnet). (Why did they
+save it as a jpeg?) The first blue in their image was only 15 threads
+wide, I figured that was a typographical mistake given every subsequent
+blue was 16, even in the repeats.
+
+According to the aforementioned web page, it was designed by June
+Prescott McRoberts, and adopted as the official state tartan on May 25,
+1989.
diff --git a/tartans/ut.tartan b/tartans/ut.tartan
new file mode 100644
index 0000000..6f3f303
--- /dev/null
+++ b/tartans/ut.tartan
@@ -0,0 +1,7 @@
+Name: Utah
+Sett: W1 B6 R6 B4 R6 G18 R6 W4
+
+Kudos to Utah for putting the sett right into 1996's SB-13. This is the
+tartan as specified by law. The [photograph on Utah's Online
+Library](http://pioneer.utah.gov/utah_on_the_web/utah_symbols/tartan.html)
+seems to have a final white threadcount of 3.
diff --git a/tartans/wa.tartan b/tartans/wa.tartan
new file mode 100644
index 0000000..685c0ab
--- /dev/null
+++ b/tartans/wa.tartan
@@ -0,0 +1,5 @@
+Name: Washington State
+Sett: W3 R6 B36 G72 LB6 BK6 Y2
+
+Adopted 1991 by the spartan [RCW
+1.20.110](http://apps.leg.wa.gov/rcw/default.aspx?cite=1.20.110).