def get_colorized_svg_image(filename, layers): """ Open the given svg file and colorise all given layers (by id) to the given colour values. The given layers argument represents a dictionary that maps any given layer to the new fill colour, which is given as a hex-value, like #rrggbb. """ # load xml (svg) xml = BeautifulSoup(open(filename), 'xml') # determine layer prefix (if any) prefix = xml.svg.get('data-prefix', '') if prefix != '': prefix += '_' # find all layers we need to colorise... for layer_id, instructions in layers.items(): el = xml.find(id='%s%s' % (prefix, layer_id)) if el is None: continue # assume a list of instructions if not isinstance(instructions, list): instructions = [instructions] style = parse_inline_style(el.get('style', '')) for instruction in instructions: # split attr:value instr = instruction.strip() p = instr.split(':') if len(p) == 1: attr = 'fill' value = instr elif len(p) == 2: attr = p[0] value = p[1] else: attr = None # skip instructions that we do not understand if attr is None: continue # skip attributes what we do not support if attr not in SUPPORTED_SVG_STYLE_OVERWRITES: continue # remove attribute if exists, for example 'fill' might be expressed # as an attribute or inline style. We will write this as inline # style, therefore we remove the corresponding attribute if it # exists... del el[attr] # if the value is hexadecimal, append a # to encode the correct # colour information if it is missing. if not value.startswith('#') and re.match(r'^[0-9a-fA-F]+$', value): value = '#' + value # add to style style[attr] = value # update element's inline style el['style'] = encode_inline_style(style) # return changed content as xml. We should be safe from any code injection # here, since bs4 will re-build and escape all style attributes... return unicode(xml)
def test_should_split_css_inline_style_by_rule(self): self.assertEqual({ 'fill': 'red', 'stroke': '#efefef' }, parse_inline_style(' fill: red; stroke: #efefef '))
def test_should_ignore_empty_rules(self): self.assertEqual({'fill': 'red'}, parse_inline_style(' fill: red; stroke;;; '))
def test_should_return_empty_dict_for_empty_inline_style(self): self.assertEqual({}, parse_inline_style(''))