Manipulating icons with Iconify Tools

Iconify Tools is a NPM package for manipulating icons. See Iconify Tools documentation.

This documentation is for version 1 of Iconify Tools. It was developed during early Iconify development, before Iconify development switched to TypeScript, so it is not fully compatible with TypeScript.

Documentation for updated Iconify Tools is available here.

Most functions require SVG to be optimized. Therefore, before doing anything else, you should optimize icon.

SVGO optimization

Function SVGO optimizes icon.

Parameters:

  1. SVG instance.
  2. Optional options object.
tools
   .SVGO(svg)
   .then((svg) => {
       // svg variable is the same as in argument. Optimizer does not create new instance of SVG class
       console.log('Optimized SVG:', svg.toString());
   })
   .catch((err) => {
       console.error(err);
   });

Want to optimize an entire collection? Use collection's promiseAll function:

collection
   .promiseAll((svg) => tools.SVGO(svg))
   .then((results) => {
       console.log('Optimized entire collection');
   })
   .catch((err) => {
       console.error(err);
   });

Some of available options (second parameter):

  • mergePaths, boolean. Merges SVG paths to reduce icon size. The default value is false.
  • convertShapeToPath, boolean. Converts SVG shapes to paths. The default value is true.
  • plugins. List of SVGO plug-ins. If set, it will override default plug-ins list and options mentioned above are ignored.
  • doublePass, boolean. If enabled, runs optimization process twice. Sometimes running optimization twice improves result. The default value is false.

Cropping images

Function Crop removes empty spaces around icon content.

Important: this function requires PhantomJS to be installed and accessible from command line! PhantomJS has been deprecated for a while, but you can still install it using HomeBrew.

Parameters:

  1. SVG instance or Collection instance.

How to crop one icon:

tools
   .Crop(svg)
   .then((svg) => {
       console.log('Cropped SVG: ' + svg.toString());
   })
   .catch((err) => {
       console.error(err);
   });

How to crop entire collection:

tools
   .Crop(collection)
   .then((collection) => {
       console.log('Cropped ' + svg.length() + ' images');
   })
   .catch((err) => {
       console.error(err);
   });

How does Crop() function work? By drawing SVG on canvas and checking all 4 sides for transparent pixels. First it appends space on all sides of SVG, until all sides have nothing but empty pixels. Then it slowly cuts all sides until it reaches pixels that aren't empty. Process doesn't take long because script checks pixels in bulk by zooming in.

When it crops SVG or Collection instance (like in examples above), each SVG instance receives additional properties that you might want to use later: _cropData. _cropData is an object with list of cropped edges: left, top, right, bottom.

Tags validation

Function Tags checks elements used in SVG, changes stylesheet into inline style and removes useless attributes.

Stylesheet parser is very simple, it parses only the basic stylesheets that are generated by some image editors. If SVG contains fishy elements that aren't vector images, such as bitmaps or scripts, it will reject with error message.

Important! Before running this function, you need to optimize SVG using tools.SVGO().

tools
   .Tags(svg)
   .then((svg) => {
       console.log('Cleaned up tags in SVG: ' + svg.toString());
   })
   .catch((err) => {
       console.error(err);
   });

This function is used for cleaning up SVG that contain a lot of junk code.

Extracting palette from SVG

Function GetPalette extracts list of colors used in icon.

This is useful if you don't know if SVG is colored or monotone.

Result is object with 2 properties:

  • colors, string[]: array of colors.
  • notices, string[]: array of error messages.

Usage:

tools.GetPalette(svg).then(result => {
   console.log('Colors used in SVG: ' + result.colors.join(', ');
   if (result.notices.length) {
       result.notices.forEach(notice => console.warn(notice));
   }
}).catch(err => {
   console.error(err);
});

To use it with entire icon set, use Collection's promiseAll function:

collection.promiseAll(svg => tools.GetPalette(svg)).then(result => {
   Object.keys(results).forEach(key => {
       console.log('Colors found in image ' + key + ': ' + result[key].colors.join(', ');
   });
}).catch(err => {
   console.error(err);
});

Replacing palette in SVG

Function ChangePalette changes colors in SVG and adds colors to shapes that are missing colors.

Parameters:

  1. SVG instance.
  2. Color changes, object or string.

Color changes object is a list of key/value pairs, where key is the old color, value is the new color.

Colors that are formatted differently are treated differently. For example, "#fff", "#ffffff" and "white" are considered to be different colors. Use GetPalette before changing palette to get list of colors because that function will also treat those colors as separate colors and will return them in the same format as in SVG.

Reserved keywords in color changes object:

  • add: color to add to shapes that are missing color. This is used when shape has fill or stroke, but does not have color value.
  • default: default replacement for colors that aren't listed in color changes.

Examples:

tools
   .ChangePalette(svg, {
       '#ff8000': '#0080ff',
       '#123': '#234',
   })
   .then((svg) => {
       // Variable "svg" in result is the same as in first parameter of ChangePalette.
       // Function changes existing SVG instance
       console.log('Changed palette');
   })
   .catch((err) => {
       console.error(err);
   });

Code above will change "#ff8000" to "#0080ff" and "#123" to "#234".

tools
   .ChangePalette(svg, 'red')
   .then((svg) => {
       console.log('Added palette to elements without palette');
   })
   .catch((err) => {
       console.error(err);
   });

Code above will add color "red" to all elements that do not have color. It is identical to this:

tools
   .ChangePalette(svg, {
       add: 'red',
   })
   .then((svg) => {
       console.log('Added palette to elements without palette');
   })
   .catch((err) => {
       console.error(err);
   });

You can also change all colors by using keyword "default":

tools
   .ChangePalette(svg, {
       default: 'green',
   })
   .then((svg) => {
       console.log('Changed all colors to green');
   })
   .catch((err) => {
       console.error(err);
   });

Or you can combine all those attributes:

tools
   .ChangePalette(svg, {
       'default': 'green',
       'add': '#000',
       '#123': '#234',
   })
   .then((svg) => {
       console.log(
           'Changed all colors to green, except for #123 that was changed to #234, added black color to elements without color'
       );
   })
   .catch((err) => {
       console.error(err);
   });

Primary use of this function in Iconify is to replace all colors in monotone icons with "currentColor" keyword and add it to shapes that are missing color values:

collection
   .promiseAll((svg) =>
       tools.ChangePalette(svg, {
           default: 'currentColor',
           add: 'currentColor',
       })
   )
   .then(() => {
       console.log('Changed color to currentColor');
   })
   .catch((err) => {
       console.error(err);
   });

Indexing shapes

Function IndexShapes is used to add unique numbers to each shape and count shapes.

This function is intended to be used when calculating stroke animations.

Parameters:

  1. SVG instance.
  2. Options object.

Options object properties:

  • ignoreTags, string[]. List of tags to ignore.
  • shapeTags, string[]. List of tags that are considered to be shapes.
  • shapeStartIndex, number. Index for first shape, default is 0.
  • shapeAttribute, string. Attribute to add to tags, default value is "data-shape-index".
  • shapeAttributeValue, string. Value for attribute mentioned above. Keyword "{index}" is replaced by index number. The default value is "{index}".
  • remove, boolean. If true, function will remove attributes instead of adding attributes.
  • shapeCallback, function. Callback to call for each shape. See src/shapes/options.js for details.
  • returnNodes, boolean. If true, function will return nodes as array instead of returning number of nodes.
tools
   .IndexShapes(svg, {
       // Attribute to set
       shapeAttribute: 'data-shape-index',
       // Attribute value. {index} is replaced with index, incrementing with each shape
       shapeAttributeValue: '{index}',
   })
   .then((shapesCount) => {
       console.log(
           'Added data-shape-index attribute to ' + shapesCount + ' shapes.'
       );
   })
   .catch((err) => {
       console.error(err);
   });

Getting shape lengths

Function ShapeLength returns lengths of all shapes as well as all shapes as cheerio objects.

Important: this function requires PhantomJS to be installed and accessible from command line! PhantomJS has been deprecated for a while, but you can still install it using HomeBrew.

Parameters:

  1. SVG instance.
tools
   .ShapeLength(svg)
   .then((results) => {
       console.log('Found ' + results.length + ' shapes:');
       results.forEach((result) => {
           console.log(
               'Shape ' +
                   result.$node.get(0).tagName +
                   ' has length of ' +
                   result.length
           );
       });
   })
   .catch((err) => {
       console.error(err);
   });