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

3 Likes

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 = {}
	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
						else:
							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)
shared.util.clipboard.writeText(svg)
1 Like

Thank you very much!

1 Like