from __future__ import (absolute_import, division, print_function,
unicode_literals)
from six.moves.configparser import RawConfigParser
from . import Draft, __version__
[docs]class WIFReader(object):
"""
A reader for a specific WIF file.
"""
# TODO
# - add support for metadata: author, notes, etc.
# - add support for warp/weft spacing and thickness
# - ensure that we're correctly handling the 'palette form' (might be only
# RGB?)
allowed_units = ('decipoints', 'inches', 'centimeters')
def __init__(self, filename):
self.filename = filename
[docs] def getbool(self, section, option):
if self.config.has_option(section, option):
return self.config.getboolean(section, option)
else:
return False
# XXX Name, author, notes, etc.
[docs] def put_warp(self, draft, wif_palette):
warp_thread_count = self.config.getint('WARP', 'Threads')
warp_units = self.config.get('WARP', 'Units').lower()
assert warp_units in self.allowed_units, \
"Warp Units of %r is not understood" % warp_units
has_warp_colors = self.getbool('CONTENTS', 'WARP COLORS')
if has_warp_colors:
warp_color_map = {}
for thread_no, value in self.config.items('WARP COLORS'):
warp_color_map[int(thread_no)] = int(value)
else:
warp_color_map = None
warp_color = None
if not warp_color_map:
# try to get warp color from WARP section
has_warp_colors = False
warp_color = self.config.getint('WARP', 'Color')
has_threading = self.getbool('CONTENTS', 'THREADING')
if has_threading:
threading_map = {}
for thread_no, value in self.config.items('THREADING'):
threading_map[int(thread_no)] = \
[int(sn) for sn in value.split(',')]
for thread_no in range(1, warp_thread_count + 1):
# NOTE: Some crappy software will generate WIFs with way more
# threads in the warp or weft section than mentioned in the
# threading. To ignore that, make sure that this thread actually
# has threading specified: otherwise it's unused.
if thread_no in threading_map:
if has_warp_colors:
color = wif_palette[warp_color_map[thread_no]]
else:
color = wif_palette[warp_color]
if has_threading:
shafts = set(draft.shafts[shaft_no - 1]
for shaft_no in threading_map[thread_no])
assert len(shafts) == 1
shaft = list(shafts)[0]
else:
shaft = None
draft.add_warp_thread(
color=color,
shaft=shaft,
)
[docs] def put_weft(self, draft, wif_palette):
weft_thread_count = self.config.getint('WEFT', 'Threads')
weft_units = self.config.get('WEFT', 'Units').lower()
assert weft_units in self.allowed_units, \
"Weft Units of %r is not understood" % weft_units
has_weft_colors = self.getbool('CONTENTS', 'WEFT COLORS')
if has_weft_colors:
weft_color_map = {}
for thread_no, value in self.config.items('WEFT COLORS'):
weft_color_map[int(thread_no)] = int(value)
else:
weft_color_map = None
weft_color = None
if not weft_color_map:
# try to get weft color from WEFT section
has_weft_colors = False
weft_color = self.config.getint('WEFT', 'Color')
has_liftplan = self.getbool('CONTENTS', 'LIFTPLAN')
if has_liftplan:
liftplan_map = {}
for thread_no, value in self.config.items('LIFTPLAN'):
liftplan_map[int(thread_no)] = \
[int(sn) for sn in value.split(',')]
has_treadling = self.getbool('CONTENTS', 'TREADLING')
if has_treadling:
treadling_map = {}
for thread_no, value in self.config.items('TREADLING'):
try:
treadles = [int(tn) for tn in value.split(',')]
except ValueError:
pass
else:
treadling_map[int(thread_no)] = treadles
for thread_no in range(1, weft_thread_count + 1):
if (has_liftplan and (thread_no in liftplan_map)) or \
(has_treadling and (thread_no in treadling_map)):
if has_weft_colors:
color = wif_palette[weft_color_map[thread_no]]
else:
color = wif_palette[weft_color]
if has_liftplan:
shafts = set(draft.shafts[shaft_no - 1]
for shaft_no in liftplan_map[thread_no])
else:
shafts = set()
if has_treadling:
treadles = set(draft.treadles[treadle_no - 1]
for treadle_no in treadling_map[thread_no])
else:
treadles = set()
draft.add_weft_thread(
color=color,
shafts=shafts,
treadles=treadles,
)
[docs] def put_tieup(self, draft):
for treadle_no, value in self.config.items('TIEUP'):
treadle = draft.treadles[int(treadle_no) - 1]
shaft_nos = [int(sn) for sn in value.split(',')]
for shaft_no in shaft_nos:
shaft = draft.shafts[shaft_no - 1]
treadle.shafts.add(shaft)
[docs] def read(self):
"""
Perform the actual parsing, and return a Draft instance.
"""
self.config = RawConfigParser()
self.config.read(self.filename)
rising_shed = self.getbool('WEAVING', 'Rising Shed')
num_shafts = self.config.getint('WEAVING', 'Shafts')
num_treadles = self.config.getint('WEAVING', 'Treadles')
liftplan = self.getbool('CONTENTS', 'LIFTPLAN')
treadling = self.getbool('CONTENTS', 'TREADLING')
assert not (liftplan and treadling), \
"WIF contains both liftplan and treadling"
assert not (liftplan and (num_treadles > 0)), \
"WIF contains liftplan and non-zero treadle count"
if self.getbool('CONTENTS', 'COLOR PALETTE'):
palette_range = self.config.get('COLOR PALETTE', 'Range')
rstart, rend = palette_range.split(',')
palette_range = int(rstart), int(rend)
else:
palette_range = 0, 255
if self.getbool('CONTENTS', 'COLOR TABLE'):
wif_palette = {}
for color_no, value in self.config.items('COLOR TABLE'):
channels = [int(ch) for ch in value.split(',')]
channels = [int(round(ch * (255. / palette_range[1])))
for ch in channels]
wif_palette[int(color_no)] = channels
else:
wif_palette = None
draft = Draft(num_shafts=num_shafts,
num_treadles=num_treadles,
rising_shed=rising_shed)
self.put_metadata(draft)
self.put_warp(draft, wif_palette)
self.put_weft(draft, wif_palette)
if treadling:
self.put_tieup(draft)
return draft
[docs]class WIFWriter(object):
"""
A WIF writer for a draft.
"""
# TODO
# - support greater color depth (may require change to Color)
def __init__(self, draft):
self.draft = draft
[docs] def write_palette(self, config):
# generate the color table and write it to the config
# return a wif_palette mapping color instances to numbers.
colors = set(thread.color.rgb for thread in
self.draft.warp + self.draft.weft)
wif_palette = {}
config.set('CONTENTS', 'COLOR TABLE', 1)
config.add_section('COLOR TABLE')
for ii, color in enumerate(colors, start=1):
val = '%d,%d,%d' % color
config.set('COLOR TABLE', str(ii), val)
wif_palette[color] = ii
config.set('CONTENTS', 'COLOR PALETTE', 1)
config.add_section('COLOR PALETTE')
config.set('COLOR PALETTE', 'Form', 'RGB')
config.set('COLOR PALETTE', 'Range', '0,255')
return wif_palette
[docs] def write_threads(self, config, wif_palette, dir):
assert dir in ('warp', 'weft')
threads = getattr(self.draft, dir)
dir = dir.upper()
config.set('CONTENTS', dir, 1)
config.add_section(dir)
config.set(dir, 'Threads', len(threads))
# XXX This should actually be stored in the draft.
config.set(dir, 'Units', 'Inches')
config.set('CONTENTS', '%s COLORS' % dir, 1)
config.add_section('%s COLORS' % dir)
for ii, thread in enumerate(threads, start=1):
config.set('%s COLORS' % dir,
str(ii),
wif_palette[thread.color.rgb])
[docs] def write_threading(self, config):
config.set('CONTENTS', 'THREADING', 1)
config.add_section('THREADING')
for ii, thread in enumerate(self.draft.warp, start=1):
shaft_string = str(self.draft.shafts.index(thread.shaft) + 1)
config.set('THREADING', str(ii), shaft_string)
[docs] def write_liftplan(self, config):
config.set('CONTENTS', 'LIFTPLAN', 1)
config.add_section('LIFTPLAN')
for ii, thread in enumerate(self.draft.weft, start=1):
shaft_nos = [self.draft.shafts.index(shaft) + 1
for shaft in thread.connected_shafts]
shaft_string = ','.join([str(shaft_no) for shaft_no in shaft_nos])
config.set('LIFTPLAN', str(ii), shaft_string)
[docs] def write_treadling(self, config):
config.set('CONTENTS', 'TREADLING', 1)
config.add_section('TREADLING')
for ii, thread in enumerate(self.draft.weft, start=1):
treadle_nos = [self.draft.treadles.index(treadle) + 1
for treadle in thread.treadles]
treadle_string = ','.join([str(treadle_no) for treadle_no in
treadle_nos])
config.set('TREADLING', str(ii), treadle_string)
[docs] def write_tieup(self, config):
config.set('CONTENTS', 'TIEUP', 1)
config.add_section('TIEUP')
for ii, treadle in enumerate(self.draft.treadles, start=1):
shaft_nos = [self.draft.shafts.index(shaft) + 1
for shaft in treadle.shafts]
shaft_string = ','.join([str(shaft_no) for shaft_no in shaft_nos])
config.set('TIEUP', str(ii), shaft_string)
[docs] def write(self, filename, liftplan=False):
assert self.draft.start_at_lowest_thread
config = RawConfigParser()
config.optionxform = str
config.add_section('CONTENTS')
self.write_metadata(config, liftplan=liftplan)
wif_palette = self.write_palette(config)
self.write_threads(config, wif_palette, 'warp')
self.write_threads(config, wif_palette, 'weft')
self.write_threading(config)
if liftplan or not self.draft.treadles:
self.write_liftplan(config)
else:
self.write_treadling(config)
self.write_tieup(config)
with open(filename, 'wb') as f:
config.write(f)