Exporting SVGs from Perspective

I have embedded an SVG in a Perspective view and edited its elements. Is there a way to export this back to a .svg file?

1 Like

Yep, but you'll have to do it yourself for now in script by generating the xml.. I can post my script when I'm back at my laptop, but it doesn't export more complex styles


If you still have the script, I'd also appreciate seeing that.

Sorry, time got away from me.
Script below.
obj is a copy of the "SVG" in the View, converted into a Py Object with json.loads / system.util.jsonDecode
The ATTR_LOOKUP is a conversion table (dictionary) of Ignition styles to its corresponding SVG style.

EDIT: Tested and working in the script console, although you'll need the clipboard functions. I've posted them elsewhere on the forum

import xml.etree.cElementTree as et
import json
import copy

def extract_svg_from_view(obj):
	#json_str = clipboard.getClipboard()
	#'[{         "type": "ia.shapes.svg",         "version": 0,         "props": {             "viewBox": "0 0 185 527.99",             "elements": [{                     "type": "path",                     "name": "rect933",                     "d": "m92.5 5c-43.75 0-87.5 30.69-87.5 92.07v425.92h175v-425.92c0-61.38-43.75-92.07-87.5-92.07z",                     "fill": {                         "paint": "#fff"                     },                     "stroke": {                         "paint": "#000",                         "linecap": "round",                         "width": "10"                     }                 }, {                     "type": "path",                     "name": "rect933-3",                     "d": "m92.5 5c-43.75 0-87.5 30.69-87.5 92.07v425.92h175v-425.92c0-61.38-43.75-92.07-87.5-92.07z",                     "fill": {                         "paint": "#fff"                     },                     "stroke": {                         "paint": "#000",                         "linecap": "round",                         "width": "10"                     }                 }, {                     "type": "group",                     "name": "g7299",                     "fill": {                         "paint": "#ff2a2a"                     },                     "stroke": {                         "paint": "#000",                         "linecap": "round",                         "width": "10"                     },                     "elements": [{                             "type": "circle",                             "name": "circle7295",                             "cx": "69.758",                             "cy": "157.43",                             "r": "64.685"                         }, {                             "type": "circle",                             "name": "path7213",                             "cx": "92.5",                             "cy": "263.99",                             "r": "64.685"                         }                     ]                 }             ]         },         "meta": {             "name": "TEST_Export"         },         "position": {             "basis": "20px"         },         "custom": {}     } ] '
	#svg_obj = json.loads(json_str)
	svg_obj = obj[0] # assume that the obj passed in is a copied "SVG" from a Perspective View which adds the SVG definition into a single item array. We want the item
	viewbox = svg_obj['props']['viewBox']
	elements = svg_obj['props']['elements']

	ATTR_LOOKUP['name'] = 'id'
	ATTR_LOOKUP['fill.paint'] = 'fill'
	ATTR_LOOKUP['fill.opacity'] = 'opacity'
	ATTR_LOOKUP['stroke.paint'] = 'stroke'
	ATTR_LOOKUP['style.stroke'] = 'stroke'
	ATTR_LOOKUP['stroke.linecap'] = 'stroke-linecap'
	ATTR_LOOKUP['stroke.width'] = 'stroke-width'
	ATTR_LOOKUP['style.strokeWidth'] = 'stroke-width'
	ATTR_LOOKUP['style.vector-effect'] = 'vector-effect'

	doc = et.Element('svg', viewBox=viewbox, version='1.1', xmlns='http://www.w3.org/2000/svg')

	not_included_SVG_elements = []
	def addElements(xmlobj, elements):
		for element in elements:
			if 'type' in element:
				attrs_dict = {}

				# collect the attributes for the current SVG element are store them in a dictionary
				for attr_name in element:
					# exclude any nested elements as they need to be added later. These are not added as attributes
					if attr_name != 'elements':
						attr = element[attr_name]

						# if the attribute is a dict in Ignition, then the dict will contain the actual attribute names
						if isinstance(attr, dict):
							for prop_name in attr:
								svg_prop_name = ATTR_LOOKUP.get('{}.{}'.format(attr_name, prop_name), 'UNSET')
								if svg_prop_name == 'UNSET':
									not_included_SVG_elements.append('{}.{}'.format(attr_name, prop_name))

								svg_prop_val = attr[prop_name]

								attrs_dict[svg_prop_name] = svg_prop_val
							attrs_dict[ATTR_LOOKUP.get(attr_name, attr_name)] = attr

				element_name = attrs_dict['type']
				if element_name == 'group':
					element_name = 'g'

				xmlobj_attr = et.SubElement(xmlobj, element_name, **attrs_dict)

				if 'elements' in element:
					attr_elements = copy.deepcopy(element['elements'])

					addElements(xmlobj_attr, attr_elements)

	addElements(doc, elements)
	#print ET.tostring(doc, encoding='utf8', method='xml')
	if not_included_SVG_elements != []:
		print "Copied to clipboard, but some SVG attributes are missing mapping. These have not been extracted {}".format(not_included_SVG_elements)
	return et.tostring(doc)	

json = shared.util.clipboard.readText()
obj = system.util.jsonDecode(json)
svg = extract_svg_from_view(obj)
1 Like

Thank you very much!

1 Like