Custom Icon Library in 8.3

From the documentation: This does not appear to be the proper location for a custom icon library in 8.3. Did a search for material.svg and it is not found. I'm assuming this is still allowed. What folder should a custom library go into now?

Use a Custom Icon Repository

The materials icon repository is a great source for icons, but if you have a custom library of icons, you can set it up to be accessible by Ignition. All icon repositories are stored as SVG files within the Gateway's Installation Directory. A typical path to an icon file will look like:

  • Windows
  • MacOS
  • Linux
C:\Program Files\Inductive Automation\Ignition\data\modules\com.inductiveautomation.perspective\icons\<repository name>.svg

You can create custom libraries by adding your own SVG file at this path. The properties inside the file are defined using XML, which

1 Like

Okay, here's the current steps.

  1. Navigate to your install directory, and in the /data/config/resources/core/ folder, create a new folder com.inductiveautomation.perspective/ (if it doesn't already exist).

  2. Within that folder create an icons/ folder.

  3. Within that folder create a <repository name>/ folder.

  4. Within that folder, create:

    • The spritesheet of your SVG, at whatever arbitrary filename you want, e.g. icons.svg.
    • A config.json file that contains a single entry, svgFileName, that contains the same name (icons.svg or whatever else you chose)
      {
       "svgFileName": "icons.svg"
      }
      
    • A resource.json file that references both config.json and your custom icons SVG:
      {
          "scope": "A",
          "version": 1,
          "restricted": false,
          "overridable": true,
          "files": [
              "config.json",
              "icons.svg"
          ],
          "attributes": {
          }
      }
      
  5. Restart the gateway (or POST the /data/api/v1/scan/config endpoint) to pick up the changed resource.

4 Likes

As an aside, I'm not sure if there's a rationale I'm not aware of for the indirection of the config.json resource. I'm going to make a case to drop it for final release, so you would just have a resource.json file pointing to the svg file (by whatever arbitrary name). There may be a complicated upgrade related reason we had to do things this way, though.

1 Like

That worked for me. Thanks.

Perfect. Thank you sir!

Any update here now that the final release is out?

Icons work the same way in the final release, though there were some changes in themes.

I haven’t been able to get the icons to open in designer by adding the icon folder as described above. I have my svg file formatted per this section of the manual: Images and Icons in Perspective | Ignition User Manual. Nothing populates in the migrated-icons folder after a gateway restart either.

Attaching the svg and json files below.

PlantPAxIcons_resource_with_readme(1).zip (18.5 KB)

Your icons file is malformed:

E [P.IconManager                 ] [15:28:30.982] [platform-executor-84]: Unable to parse PlantPAxIcons icon library collection=core
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x0) was found in the element content of the document.
	at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:262)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:342)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.computeLibraryAndCache(IconManagerImpl.java:182)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.lambda$onResourceAdded$5(IconManagerImpl.java:150)
	at java.base/java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1916)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.onResourceAdded(IconManagerImpl.java:150)
	at com.inductiveautomation.ignition.gateway.config.NamedResourceHandler$Lifecycle.onAfterChanges(NamedResourceHandler.java:705)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycle$LifecycleResourceListener.onAfterChanges(ResourceCollectionLifecycle.java:183)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.notifyListener(AbstractResourceCollection.java:386)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.notifyResourceListeners(AbstractResourceCollection.java:315)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.updateEffectiveState(AbstractResourceCollection.java:156)
	at com.inductiveautomation.ignition.common.resourcecollection.RuntimeResourceCollection.applyChange(RuntimeResourceCollection.java:267)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.lambda$updateOrStartAffected$5(ResourceCollectionLifecycleFactory.java:210)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.updateOrStartAffected(ResourceCollectionLifecycleFactory.java:190)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.collectionUpdated(ResourceCollectionLifecycleFactory.java:167)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.notifyCollectionChanged(ResourceCollectionManagerImpl.java:1610)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.notifyCollectionChanged(ResourceCollectionManagerImpl.java:1594)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$onFileTreeChange$27(ResourceCollectionManagerImpl.java:1515)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$onFileTreeChange$28(ResourceCollectionManagerImpl.java:1514)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$wrapNotificationTask$0(ResourceCollectionManagerImpl.java:204)
	at com.inductiveautomation.ignition.common.util.ExecutionQueue$PollAndExecute.run(ExecutionQueue.java:238)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
E [P.IconManager                 ] [15:28:30.985] [platform-executor-84]: Unable to parse PlantPAxIcons icon library collection=core
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x0) was found in the element content of the document.
	at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:262)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:342)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.computeLibraryAndCache(IconManagerImpl.java:182)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.lambda$onResourcesUpdated$7(IconManagerImpl.java:167)
	at java.base/java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1916)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.lambda$onResourcesUpdated$8(IconManagerImpl.java:166)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at com.inductiveautomation.perspective.gateway.assets.icons.IconManagerImpl.onResourcesUpdated(IconManagerImpl.java:166)
	at com.inductiveautomation.ignition.gateway.config.NamedResourceHandler$Lifecycle.onAfterChanges(NamedResourceHandler.java:720)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycle$LifecycleResourceListener.onAfterChanges(ResourceCollectionLifecycle.java:183)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.notifyListener(AbstractResourceCollection.java:386)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.notifyResourceListeners(AbstractResourceCollection.java:315)
	at com.inductiveautomation.ignition.common.resourcecollection.AbstractResourceCollection.updateEffectiveState(AbstractResourceCollection.java:156)
	at com.inductiveautomation.ignition.common.resourcecollection.RuntimeResourceCollection.applyChange(RuntimeResourceCollection.java:267)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.lambda$updateOrStartAffected$5(ResourceCollectionLifecycleFactory.java:210)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.updateOrStartAffected(ResourceCollectionLifecycleFactory.java:190)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionLifecycleFactory$1.collectionUpdated(ResourceCollectionLifecycleFactory.java:167)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.notifyCollectionChanged(ResourceCollectionManagerImpl.java:1610)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.notifyCollectionChanged(ResourceCollectionManagerImpl.java:1594)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$onFileTreeChange$27(ResourceCollectionManagerImpl.java:1515)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$onFileTreeChange$28(ResourceCollectionManagerImpl.java:1514)
	at com.inductiveautomation.ignition.gateway.resourcecollection.ResourceCollectionManagerImpl.lambda$wrapNotificationTask$0(ResourceCollectionManagerImpl.java:204)
	at com.inductiveautomation.ignition.common.util.ExecutionQueue$PollAndExecute.run(ExecutionQueue.java:238)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)

There's a bunch of invalid binary characters: