@esri/calcite-ui-icons
Version:
A collection of UI SVG icons created by Esri for applications.
219 lines (208 loc) • 7.88 kB
JavaScript
const fs = require('fs');
const svg2img = require('svg2img');
const path = require('path');
const yargs = require('yargs');
const options = yargs
.usage('Usage: -n <name of icon, omit if doing bulk>, \n-s <output size, defaults to 24>, \n-o <output path (defaults to ./output)>, \n-p <target platform (e.g. ios) \n-i <16, 24, 32, omit for 16>')
.option('n', { alias: 'name', describe: 'name of icon, without -32.svg; omit to convert all icons', type: 'string', demandOption: false })
.option('o', { alias: 'outputDir', describe: 'output path, relative to this script', type: 'string', demandOption: false })
.option('p', { alias: 'outputPlatform', describe: 'target platform, valid options are: ios', type: 'string', demandOption: false })
.option('i', { alias: 'inSize', describe: 'source svg variant, defaults to 16', type: 'string', demandOption: false })
.option('s', { alias: 'outSize', describe: 'size of output image', type: 'string', demandOption: false})
.argv;
/**
* Converts a single svg to png, with given width & height values. The function will automatically append '.png'
* @param {string} svgFilePath - filepath to icon .svg
* @param {int} width - width of output file
* @param {int} height - height of output file
* @param {string} outputBasePath - base directory in which to store output
* @param {string} outputName - name of output png image, excluding '.png'
* @param {string} outputSuffix - suffix appended to output file name (ex, '@2x')
*/
function convertSingleIconToPng(svgFilePath, width, height, outputBasePath, outputName, outputSuffix=null) {
// make sure output base path exists
if (!fs.existsSync(outputBasePath)) {
fs.mkdirSync(outputBasePath, {
recursive: true
});
}
// concatenate real output path
let real_output_path = path.join(outputBasePath, outputName);
if (outputSuffix) {
real_output_path += outputSuffix
}
real_output_path += '.png'
// convert and save the image
svg2img(svgFilePath, { 'width': width, 'height': height }, function (error, buffer) {
if (error){
console.log(error);
process.exit(1);
}
fs.writeFileSync(real_output_path, buffer);
});
}
/**
* Creates an ImageSet (including Contents.json file) for an icon
* @param {string} svgFilePath - filepath to icon .svg
* @param {int} width - width of output file @1x
* @param {int} height - height of output file @1x
* @param {string} outputBasePath - base directory in which to store output
* @param {string} outputName - name of output png image, excluding '.png'
*/
function convertIconToXcodeImageSet(svgFilePath, width, height, outputBasePath, outputName) {
const outputImagesetPath = path.join(outputBasePath, outputName + '.imageset');
// Create images at 3 sizes
convertSingleIconToPng(svgFilePath, width, height, outputImagesetPath, outputName, '@1x');
convertSingleIconToPng(svgFilePath, width * 2, height * 2, outputImagesetPath, outputName, '@2x');
convertSingleIconToPng(svgFilePath, width * 3, height * 3, outputImagesetPath, outputName, '@3x');
// read template
const imagesetTemplatePath = path.join(__dirname, 'templates', 'imageset.json');
// create Contents.json for asset catalog asset
fs.readFile(imagesetTemplatePath, 'utf8', function (error, buffer) {
if (error) {
console.log(error);
process.exit(1);
}
const contentsJsonBuffer = buffer.replace(/\$\{NAME\}/g, outputName);
const contentsJsonOutputPath = path.join(outputImagesetPath, 'Contents.json');
fs.writeFileSync(contentsJsonOutputPath, contentsJsonBuffer)
});
}
/**
* Indexes all calcite icons contained in directory at path
* @param {string} baseIconPath - path to calcite .svg icons directory
*/
async function indexCalciteIcons(baseIconPath) {
return new Promise(resolve => {
var iconIndex = {};
fs.readdir(baseIconPath, function (error, files) {
if (error) {
console.log(error);
process.exit(1);
}
files.forEach(function (file) {
// strip all files of file size information, catalog in an index
var base_name = path.basename(file);
base_name = base_name.replace('.svg', '');
var size = undefined;
if (base_name.includes('-16')) {
base_name = base_name.replace('-16', '');
size = 16;
}
else if (base_name.includes('-24')) {
base_name = base_name.replace('-24', '');
size = 24;
}
else if (base_name.includes('-32')) {
base_name = base_name.replace('-32', '');
size = 32;
}
if (!iconIndex[base_name]) {
iconIndex[base_name] = {}
}
iconIndex[base_name][size] = path.join(baseIconPath, file);
});
resolve(iconIndex);
});
});
}
/**
* Indexes all calcite icons contained in directory at path
* @param {string} xcAssetsBaseDirectory - path where to derive calcite.xcassets
*/
async function createCalciteXCAssets(xcAssetsBaseDirectory) {
return new Promise(resolve => {
// Put in .xcassets folder
var directory = path.join(xcAssetsBaseDirectory, 'calcite.xcassets');
// Make sure dir exists
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, {
recursive: true
});
}
// read contents.json template
let template_path = path.join(__dirname, 'templates', 'xcassets.json');
// write out file
fs.readFile(template_path, 'utf8', function (error, buffer) {
if (error) {
console.log(error);
process.exit(1);
}
const contents_output_path = path.join(directory, 'Contents.json');
fs.writeFile(contents_output_path, buffer, function (error) {
resolve(directory);
});
});
});
}
async function main() {
// index all calcite icons
let iconIndex = await indexCalciteIcons('./icons/');
// establish output root path
var outputRoot = path.join(__dirname, 'output')
if (options.outputDir) {
outputRoot = path.join(__dirname, options.outputDir);
}
// establish input size
var inputSize = 24;
if (options.inSize === '16'){
inputSize = 16;
} else if (options.inSize === '24'){
inputSize = 24;
} else if (options.inSize === '32'){
inputSize = 32;
} else if (options.outSize) {
let size = parseInt(options.outSize);
if (size < 24) {
inputSize = 16;
} else if (size < 32) {
inputSize = 24;
} else if (size >= 32) {
inputSize = 32;
}
}
// establish output size (in pixels)
var outputSize = 24;
if (options.outSize) {
let size = parseInt(options.outSize);
if (size) {
outputSize = size;
}
}
// ensure icon name is valid, checking index
if (options.name) {
if (!(options.name in iconIndex)) {
console.log("Invalid icon name " + options.name);
process.exit(1);
}
}
// build xcassets if output for iOS
if (options.outputPlatform === 'ios') {
let xcAssetsDirectory = await createCalciteXCAssets(outputRoot);
if (options.name) {
let name = options.name;
let file = iconIndex[name][inputSize];
convertIconToXcodeImageSet(file, outputSize, outputSize, xcAssetsDirectory, name);
}
else {
for (let key in iconIndex) {
let file = iconIndex[key][inputSize];
convertIconToXcodeImageSet(file, outputSize, outputSize, xcAssetsDirectory, key)
}
}
} else { // platform is not ios, render plain png
if (options.name) {
let name = options.name;
let file = iconIndex[name][inputSize];
convertSingleIconToPng(file, outputSize, outputSize, outputRoot, name, undefined);
}
else {
for (let key in iconIndex) {
let file = iconIndex[key][inputSize];
convertSingleIconToPng(file, outputSize, outputSize, outputRoot, key, undefined);
}
}
}
}
main();