auto-icon
Version:
Automatic icon resizing for Reactnative
249 lines (227 loc) • 6.06 kB
JavaScript
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('');
});