Custom Perspective Icon SVG Syntax

I am working on converting an open-source icon library into the format necessary for Perspective, and I am not finding great documentation on syntax that the SVG renderer is ignoring vs accepting.

Here is the repo: https://lucide.dev

An example SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
</svg>

My example converted version:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="transparent" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
	<g class="icon" id="activity">
		<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
	</g>
</svg>

But I am noticing that I can't get it to recognize the additional props in the <svg> tag other than viewBox. So I am always getting a greyed out icon, unless I add properties in the designer to override fill and stroke

EDIT: It looks like the icon selection popup renders the stroke attribute in the svg tag accurately, but not the fill.

EDIT #2: It looks like if I move the styling syntax in to the group tag it works as well, just not the svg tag... so maybe this is a bug?

Also a "Crash the designer" but that this identified, there are a handful of values that can cause the designer to crash when you open the icon viewer if found inside the icons svg.

For example this is where I have fill="transparent" in the group property of an icon

You can kind of see the error in the output console, but the whole designer freezes up and I can't go select the text to share the full exception.

It does this whenever I have fill=var(--icon) or fill="transparent"

These would make great support tickets :slight_smile:

You make a good point, but just imagine the benefit all the random people following behind me will get that don't have support contracts!

Also I just didn't have time to make a call when I posted it. lol

To anyone curious who comes after this, here is a simple python script that converts (at least that) folder of .svg files into the icon library structure needed for Perspective.

import os, re


# Iterate through a folder of svg files and add them to one svg repo
folder = './myFolder'
repo = './myFolder.svg'
repo = open(repo, 'w')

xml_base = '<?xml version="1.0" encoding="utf-8"?>\n' \
		   '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n' \
		   '\t<defs>\n' \
			'\t\t<style>\n' \
			'\t\t\t.icon { display: none }\n' \
			'\t\t\t.icon:target { display: inline }\n' \
			'\t\t</style>\n' \
			'\t</defs>\n'

repo.write(xml_base)

base_tab_count = 1

for filename in os.listdir(folder):
	if filename.endswith(".svg"):
		base_tabs = '\t' * base_tab_count
		repo.write('\n%s<!--%s-->\n' % (base_tabs, filename[:-4]))
		repo.write('%s<svg viewBox="0 0 24 24" width="24" height="24">\n' % base_tabs)
		svg = open(folder + '/' + filename, 'r')
		for line in svg:
			# If the line starts with <svg, use a regex to replace the xmlns and width/height attributes
			if line.startswith('<svg'):
				line = line.replace('<svg', '<g class="icon" id="%s"' % filename[:-4])
				line = re.sub(r' xmlns="[^"]+"', '', line)
				line = re.sub(r' width="[^"]+"', '', line)
				line = re.sub(r' height="[^"]+"', '', line)
				line = re.sub(r' viewBox="[^"]+"', '', line)
				line = re.sub(r' fill="[^"]+"', ' fill="none"', line)
				line = re.sub(r' stroke="[^"]+"', ' stroke="black"', line)

			if line.startswith('</svg'):
				line = line.replace('</svg', '</g')
			
			if line != '\n':
				repo.write("%s\t%s" % (base_tabs, line))
			
		svg.close()
		repo.write('\n%s</svg>\n' % base_tabs)

repo.write('\n</svg>')
repo.close()

You are using 8.1.22 right? it has some recent svg changes^^

Why not use an XML library? I use xmltodict in python 3.9
Not sure if it's got any C dependencies... But otherwise there should be a Java XML library you can use

Yes sir 8.1.22

To be fair, GitHub copilot wrote most of the script, I was just along for the ride

This was beautiful. Thank you for sharing

What a bummer!:
image

That was a well delivered point

I am trying to get an existing working SVG into the correct format for an icon SVG.

I add the symbol with the class and id but I'm not sure what to do with the extra "g" layers?

<svg xmlns="http://www.w3.org/2000/svg">
    <symbol class="icon" id="ETECH" viewBox="0 0 24.8 24.8">
        <g id="Layer_2" data-name="Layer 2">
        <g id="Layer_1-2" data-name="Layer 1">
<path d="M14.3,7.8a1.4,1.4,0,0,0,1-.2l5.4-5.5,2,2L17.2,9.5a1.4,1.4,0,0,0-.2,1,1.1,1.1,0,0,0,.9.5h6.9V0h-11V6.9A1.1,1.1,0,0,0,14.3,7.8Z"/><circle cx="12.4" cy="12.4" r="1.7"/><path d="M6.9,11a1.1,1.1,0,0,0,.9-.5,1.4,1.4,0,0,0-.2-1L2.1,4.1l2-2L9.5,7.6a1.4,1.4,0,0,0,1,.2,1.1,1.1,0,0,0,.5-.9V0H0V6.2L4.8,11Z"/><path d="M24.8,13.8H17.9a1.1,1.1,0,0,0-.9.5,1.4,1.4,0,0,0,.2,1l5.5,5.4-2,2-5.4-5.5a1.4,1.4,0,0,0-1-.2,1.1,1.1,0,0,0-.5.9V20l4.8,4.8h6.2v-11Z"/><rect x="2.1" y="18" width="6.6" height="2.76" transform="translate(-12.1 9.5) rotate(-45)"/><rect x="11" y="22.1" width="2.8" height="2.76"/><rect y="11" width="2.8" height="2.76"/>
        </g></g>
    </symbol>
</svg>

Not sure what the layers are for but removing them got it working.

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  
 
    <!--E TECH Mark icon-->
    <svg viewBox="0 0 24 24">
        <g id="ETECHMark">
		<path d="M14.3,7.8a1.4,1.4,0,0,0,1-.2l5.4-5.5,2,2L17.2,9.5a1.4,1.4,0,0,0-.2,1,1.1,1.1,0,0,0,.9.5h6.9V0h-11V6.9A1.1,1.1,0,0,0,14.3,7.8Z"/><circle cx="12.4" cy="12.4" r="1.7"/><path d="M6.9,11a1.1,1.1,0,0,0,.9-.5,1.4,1.4,0,0,0-.2-1L2.1,4.1l2-2L9.5,7.6a1.4,1.4,0,0,0,1,.2,1.1,1.1,0,0,0,.5-.9V0H0V6.2L4.8,11Z"/><path d="M24.8,13.8H17.9a1.1,1.1,0,0,0-.9.5,1.4,1.4,0,0,0,.2,1l5.5,5.4-2,2-5.4-5.5a1.4,1.4,0,0,0-1-.2,1.1,1.1,0,0,0-.5.9V20l4.8,4.8h6.2v-11Z"/><rect x="2.1" y="18" width="6.6" height="2.76" transform="translate(-12.1 9.5) rotate(-45)"/><rect x="11" y="22.1" width="2.8" height="2.76"/><rect y="11" width="2.8" height="2.76"/>
        </g>
    </svg>  
</svg>

I've often found when attempting to convert an open-source library to Ignition's format, the coloring doesn't always work correctly because some icons are designed to accept a stroke color and Ignition applies a fill color.

Inkscape can convert strokes to paths and also has a nice command line tool for it. if you have it installed, you run this PowerShell command on a folder of SVGs to convert everything to paths.

$svgFolder = "."   # <-- folder path for svgs
$files = Get-ChildItem -Path $svgFolder -Filter *.svg
foreach ($f in $files) {
    & "C:\Program Files\Inkscape\bin\inkscapecom.com" "$($f.FullName)" --actions="select-all;object-stroke-to-path;export-filename:$($f.FullName);export-do" --export-plain-svg
}

This way, when Ignition applies a fill color, you end up with this:

Instead of this:

You may get some distortion during the conversion, but it generally works quite well.

All of Google's icons use paths and never strokes. Strokes are less predictable in how they will render (scaling, inside/centre/outside path, end caps, etc.). Good to know though about being able to bulk fix them!