Fixes to parse all gen198 genomes. Named palettes.

This commit is contained in:
Steven Robertson 2017-04-20 13:54:46 -07:00
parent d1228ac303
commit f64cf79d8d
3 changed files with 143 additions and 1 deletions

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python2 #!/usr/bin/env python2
import base64 import base64
import binascii
import warnings import warnings
import xml.parsers.expat import xml.parsers.expat
import numpy as np import numpy as np
@ -28,9 +29,17 @@ class XMLGenomeParser(object):
assert self._flame is None assert self._flame is None
self._flame = dict(attrs) self._flame = dict(attrs)
self._flame['xforms'] = [] self._flame['xforms'] = []
self._flame['palette'] = np.ones((256, 4), dtype=np.float32) if attrs.get('palette'):
pal = XMLPaletteParser.lookup(int(attrs['palette']))
else:
pal = np.ones((256, 4), dtype=np.float32)
self._flame['palette'] = pal
elif name == 'xform': elif name == 'xform':
if 'color' in attrs:
# Color sometimes has an extra param that is unused by flam3
attrs['color'] = attrs['color'].strip().split()[0]
self._flame['xforms'].append(dict(attrs)) self._flame['xforms'].append(dict(attrs))
self._flame['xforms']
elif name == 'finalxform': elif name == 'finalxform':
self._flame['finalxform'] = dict(attrs) self._flame['finalxform'] = dict(attrs)
elif name == 'color': elif name == 'color':
@ -50,6 +59,58 @@ class XMLGenomeParser(object):
parser.parser.Parse(src, True) parser.parser.Parse(src, True)
return parser.flames return parser.flames
class XMLPaletteParser(object):
_names, _numbers = None, None
_locations = [
'/usr/local/share/flam3/flam3-palettes.xml',
'/usr/share/flam3/flam3-palettes.xml',
]
def __init__(self, src):
self.names, self.numbers = {}, {}
self.parser = xml.parsers.expat.ParserCreate()
self.parser.StartElementHandler = self.start_element
self.parser.EndElementHandler = self.end_element
self.parser.Parse(src, True)
def start_element(self, name, attrs):
if name == 'palette':
data = binascii.a2b_hex(
attrs['data'].replace('\n', '').replace(' ', ''))
pal = np.fromstring(data, 'u1').reshape((256, 4)) / 255.0
if 'number' in attrs:
self.numbers[int(attrs['number'])] = pal
if 'name' in attrs:
self.names[attrs['name']] = pal
def end_element(self, name):
pass
@classmethod
def _load(cls):
src = None
for loc in cls._locations:
try:
with open(loc) as fp:
src = fp.read()
break
except:
pass
if not src:
raise IOError("Couldn't find a palettes XML file")
parser = cls(src)
cls._names, cls._numbers = parser.names, parser.numbers
@classmethod
def lookup(cls, key, isname=False):
if not cls._names:
cls._load()
if isname:
return np.array(cls._names[key])
else:
return np.array(cls._numbers[key])
def convert_affine(aff, animate=False): def convert_affine(aff, animate=False):
xx, yx, xy, yy, xo, yo = vals = map(float, aff.split()) xx, yx, xy, yy, xo, yo = vals = map(float, aff.split())
if vals == [1, 0, 0, 1, 0, 0]: return None if vals == [1, 0, 0, 1, 0, 0]: return None

View File

View File

@ -0,0 +1,81 @@
import unittest
import binascii
import numpy as np
from cuburn.genome import convert
def _make_palette_src():
values = np.zeros((256,4), 'u1')
values[:,0] = range(256)
values[:,1] = 1
values[:,2] = 2
values[:,3] = 3
# leave a newline in to make sure those get stripped
return """<palettes><palette number="0" name="synthetic" data="%s
"/></palettes>""" % binascii.b2a_hex(values.tostring())
def _make_genome_src(palette=False):
src = """
<flame time="0" size="1280 960" center="0.01 0.02" scale="40" oversample="2"
filter="1" quality="500" batches="50" brightness="4" gamma="4"
url="test.com" nick="strobe" {paletteidx}>
{color}
<xform weight="0.1" color="0" hyperbolic="0.1"
coefs="01 0.2 -0.3 0.4 -0.5 0.6"/>
</flame>"""
args = {'paletteidx': '', 'color': ''}
if palette:
args['paletteidx'] = 'palette="0"'
else:
args['color'] = '<color index="0" rgb="1 2 3"/>'
return src.format(**args)
class XMLPaletteParserTest(unittest.TestCase):
def test_parse(self):
parser = convert.XMLPaletteParser(_make_palette_src())
self.assertIn('synthetic', parser.names)
self.assertIn(0, parser.numbers)
self.assertEquals([0,1/255.,2/255.,3/255.], list(parser.numbers[0][0]))
self.assertEquals([1,1/255.,2/255.,3/255.], list(parser.numbers[0][255]))
class ConversionTest(unittest.TestCase):
def test_parse(self):
parsed = convert.XMLGenomeParser.parse(_make_genome_src())
converted = convert.flam3_to_node(parsed[0])
palette = converted.pop('palette')
self.maxDiff = None
self.assertEquals(dict(
type='node',
author=dict(url='http://test.com', name='strobe'),
camera=dict(dither_width=1.0, scale=0.03125,
center=dict(x=0.01, y=0.02)),
filters=dict(
logscale=dict(brightness=4.0),
colorclip=dict(gamma=4.0)),
xforms={
'0': dict(
color=0.0,
variations=dict(hyperbolic=dict(weight=0.1)),
pre_affine=dict(
spread=32.220017414088105,
angle=[20.91008494006789, -360],
magnitude=dict(x=1.019803902718557, y=0.5),
offset=dict(x=-0.5, y=-0.6)),
weight=0.1)
}), converted)
self.assertEquals('rgb8', palette[0])
self.assertEquals('AQID////', palette[1][:8])
def test_parse_stock_palette(self):
try:
convert.XMLPaletteParser.lookup(0)
except:
# No system palettes installed, just skip the test
raise
parsed = convert.XMLGenomeParser.parse(_make_genome_src(True))
converted = convert.flam3_to_node(parsed[0])
palette = converted['palette']
self.assertEquals('rgb8', palette[0])
self.assertEquals('ALnqAMHu', palette[1][:8])