UNPKG

auto-icon

Version:

Automatic icon resizing for Reactnative

249 lines (227 loc) 6.06 kB
var fs = require('fs-extra'); var path = require('path'); var xml2js = require('xml2js'); var ig = require('imagemagick'); var colors = require('colors'); var _ = require('underscore'); var Q = require('q'); var argv = require('minimist')(process.argv.slice(2)); var packages = JSON.parse(fs.readFileSync('package.json')); /** * @var {Object} settings - names of the config file and of the icon image */ var settings = {}; var projectName; // settings.CONFIG_FILE = argv.config || 'config.xml'; settings.ICON_FILE = argv.icon || 'icon.png'; projectName = argv.name || packages.name; // settings.OLD_XCODE_PATH = argv['xcode-old'] || false; /** * Check which platforms are added to the project and return their icon names and sizes * * @param {String} projectName * @return {Promise} resolves with an array of platforms */ var getPlatforms = function () { var deferred = Q.defer(); var platforms = []; var xcodeFolder = '/Images.xcassets/AppIcon.appiconset/'; // console.log(packages); platforms.push({ name : 'ios', // TODO: use async fs.exists isAdded : fs.existsSync('platforms/ios'), iconsPath : 'ios/' + projectName + xcodeFolder, icons : [ { name: 'icon-20@2x.png', size : 40 }, { name: 'icon-20@3x.png', size : 60 }, { name: 'icon-29@2x.png', size : 58 }, { name: 'icon-29@3x.png', size : 87 }, { name: 'icon-40@2x.png', size : 80 }, { name: 'icon-40@3x.png', size : 120 }, { name: 'icon-60@2x.png', size : 120 }, { name: 'icon-60@3x.png', size : 180 }, { name: 'icon-1024.png', size : 1024 } ] }); // TODO: add missing platforms deferred.resolve(platforms); return deferred.promise; }; /** * @var {Object} console utils */ var display = {}; display.success = function (str) { str = '✓ '.green + str; console.log(' ' + str); }; display.error = function (str) { str = '✗ '.red + str; console.log(' ' + str); }; display.header = function (str) { console.log(''); console.log(' ' + str.cyan.underline); console.log(''); }; /** * Resizes, crops (if needed) and creates a new icon in the platform's folder. * * @param {Object} platform * @param {Object} icon * @return {Promise} */ var generateIcon = function (platform) { // console.log(platform[0].icons); var platform = platform[0]; var icon = platform.icons; var deferred = Q.defer(); var srcPath = settings.ICON_FILE; var platformPath = srcPath.replace(/\.png$/, '-' + platform.name + '.png'); if (fs.existsSync(platformPath)) { srcPath = platformPath; } _.map(icon,function (icon) { // console.log(icon); var dstPath = platform.iconsPath + icon.name; var dst = path.dirname(dstPath); if (!fs.existsSync(dst)) { fs.mkdirsSync(dst); } ig.resize({ srcPath: srcPath, dstPath: dstPath, quality: 1, format: 'png', width: icon.size, height: icon.size } , function(err, stdout, stderr){ if (err) { deferred.reject(err); } else { deferred.resolve(); display.success(icon.name + ' created'); } }); }); var fiximg = []; fiximg.push({platform:platform}); deferred.resolve(fiximg); return deferred.promise; }; /** * writeJson */ var writeJson = function (fiximg) { var fiximg = fiximg[0]; // console.log(fiximg); var deferred = Q.defer(); var imgs = [ { "filename": "icon-20@2x.png", "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "filename": "icon-20@3x.png", "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "filename": "icon-29@2x.png", "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "filename": "icon-29@3x.png", "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "filename": "icon-40@2x.png", "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "filename": "icon-40@3x.png", "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "filename": "icon-60@2x.png", "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "filename": "icon-60@3x.png", "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "filename": "icon-1024.png", "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ]; function readText(pathname) { var bin = fs.readFileSync(pathname); if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) { bin = bin.slice(3); } return bin.toString('utf-8'); } fs.readFile(fiximg.platform.iconsPath+'Contents.json','utf8',function (err, data) { if(err) console.log(err); console.log('fixed contents.json'); var test1=JSON.parse(data); test1.images=[]; test1.images=imgs; // _.map(imgs,function (item) { // test1.images.push(item); // }); var t = JSON.stringify(test1); // console.log(t); fs.writeFileSync(fiximg.platform.iconsPath+'Contents.json',t) }); return deferred.promise; } /** * Checks if a valid icon file exists * * @return {Promise} resolves if exists, rejects otherwise */ var validIconExists = function () { var deferred = Q.defer(); fs.exists(settings.ICON_FILE, function (exists) { if (exists) { display.success(settings.ICON_FILE + ' exists'); deferred.resolve(); } else { display.error(settings.ICON_FILE + ' does not exist'); deferred.reject(); } }); return deferred.promise; }; display.header('Checking Project & Icon'); validIconExists() .then(getPlatforms) .then(generateIcon) .then(writeJson) .catch(function (err) { if (err) { console.log(err); } }).then(function () { console.log(''); });