Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysztof-o committed Sep 19, 2013
1 parent 5d99e21 commit 74bbdf9
Show file tree
Hide file tree
Showing 15 changed files with 262 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
npm-debug.log
.idea
*.iml
export
Expand Down
2 changes: 1 addition & 1 deletion example/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var FILES = [
__dirname + '/assets/500x500.jpg'
];

spritesheet.generate(FILES, {name: 'spritesheet', 'path': __dirname}, function (err) {
spritesheet(FILES, {name: 'generator', 'path': __dirname}, function (err) {
if (err) throw err;

console.log('Spritesheet successfully generated in', __dirname);
Expand Down
Binary file modified example/spritesheet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 44 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,48 @@
#!/usr/bin/env node
module.exports = require('./lib/spritesheet');
var generator = require('./lib/generator');
var async = require('async');

module.exports = generate;

if (!module.parent) {
//todo: command line usage
}
}

/**
* generates spritesheet
* @param {string[]} files path to image files
* @param {object} options
* @param {string} options.name name of the generated spritesheet
* @param {string} options.path path to the generated spritesheet
* @param {boolean} options.square texture should be square
* @param {boolean} options.powerOfTwo texture's size (both width and height) should be a power of two
* @param {function} callback
*/
function generate(files, options, callback) {
files = files.map(function (name) {
return {name: name};
});
options = options || {};
options.imageFile = options.name + '.png';
options.dataFile = options.name + '.xml';
options.path = options.path ? options.path + '/' : '';
options.square = options.square || true;
options.powerOfTwo = options.powerOfTwo || true;


async.waterfall([
function (callback) {
generator.getImagesSizes(files, callback);
},
function (files, callback) {
generator.determineCanvasSize(files, options, callback);
},
function (options, callback) {
generator.generateImage(files, options, callback);
},
function (callback) {
generator.generateData(files, options, callback);
}
],
callback);
}
90 changes: 40 additions & 50 deletions lib/spritesheet.js → lib/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,13 @@ var exec = require('child_process').exec;
var Handlebars = require('handlebars');
var fs = require('fs');
var binpacking = require('binpacking');
var async = require('async');

/**
*
* @param {string[]} files path to image files
* @param {object} options
* @param {string} options.name name of the generated spritesheet
* @param {string} options.path path to the generated spritesheet
* @param {bool} options.square texture should be square
* @param {bool} options.powerOfTwo texture's size (both width and height) should be a power of two
* @param callback
* Iterates through given files and gets its size
* @param {object[]} files
* @param {function} callback
*/
exports.generate = function (files, options, callback) {
files = files.map(function (name) {
return {name: name};
});
options = options || {};
options.imageFile = options.name + '.png';
options.dataFile = options.name + '.xml';
options.path = options.path ? options.path + '/' : '';
options.square = true || options.square;
options.powerOfTwo = true || options.powerOfTwo;


async.series([
function (callback) {
getImagesSizes(files, options, callback);
},
function (callback) {
determineCanvasSize(files, options, callback);
},
function (callback) {
generateImage(files, options, callback);
},
function (callback) {
generateData(files, options, callback);
}
],
callback);
};


function getImagesSizes(files, options, callback) {
exports.getImagesSizes = function (files, callback) {
var fileNames = files.map(function (file) {
return file.name;
});
Expand All @@ -61,11 +25,19 @@ function getImagesSizes(files, options, callback) {
files[i].height = parseInt(size[0], 10);
});

callback(null);
callback(null, files);
})
}
};

function determineCanvasSize(files, options, callback) {
/**
* Determines texture size using bin packing algorithm
* @param {object[]} files
* @param {object} options
* @param {object} options.square canvas width and height should be equal
* @param {object} options.powerOfTwo canvas width and height should be power of two
* @param {function} callback
*/
exports.determineCanvasSize = function (files, options, callback) {
files.forEach(function (item) {
item.w = item.width;
item.h = item.height;
Expand Down Expand Up @@ -100,26 +72,44 @@ function determineCanvasSize(files, options, callback) {
options.height = roundToPowerOfTwo(options.height);
}

callback();
}
callback(null, options);
};

function generateImage(files, options, callback) {
/**
* generates texture data file
* @param {object[]} files
* @param {object} options
* @param {string} options.path path to image file
* @param {string} options.imageFile image file name
* @param {function} callback
*/
exports.generateImage = function (files, options, callback) {
var command = ['convert -size ' + options.width + 'x' + options.height + ' xc:none'];
files.forEach(function (file) {
command.push(file.name + ' -geometry +' + file.x + '+' + file.y + ' -composite');
});
command.push(options.path + options.imageFile);

exec(command.join(' \\'), callback);
}
exec(command.join(' \\'), function () {
callback(null);
});
};

function generateData(files, options, callback) {
/**
* generates texture data file
* @param {object[]} files
* @param {object} options
* @param {string} options.path path to data file
* @param {string} options.dataFile data file name
* @param {function} callback
*/
exports.generateData = function (files, options, callback) {
var tempateContent = fs.readFileSync('template/starling.template', 'utf-8');
var template = Handlebars.compile(tempateContent);
options.files = files;
var result = template(options);
fs.writeFile(options.path + options.dataFile, result, callback);
}
};

/**
* Rounds a given number to to next number which is power of two
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spritesheet.js",
"version": "0.1.0",
"version": "0.1.1",
"description": "Spritesheet generator",
"main": "index.js",
"directories": {
Expand All @@ -13,7 +13,10 @@
"handlebars": "~1.0.12",
"underscore": "~1.5.2"
},
"devDependencies": {},
"devDependencies": {
"mocha" : "*",
"expect.js" : "~0.2.0"
},
"scripts": {
"test": "mocha test"
},
Expand Down
11 changes: 11 additions & 0 deletions test/data.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions test/data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<TextureAtlas imagePath="">

<SubTexture name="/Users/Krzysztof/dev/projects/spritesheet.js/test/fixtures/50x50.jpg" x="0" y="0" width="50" height="50"/>

<SubTexture name="/Users/Krzysztof/dev/projects/spritesheet.js/test/fixtures/100x100.jpg" x="0" y="0" width="100" height="100"/>

<SubTexture name="/Users/Krzysztof/dev/projects/spritesheet.js/test/fixtures/200x200.jpg" x="0" y="0" width="200" height="200"/>

<SubTexture name="/Users/Krzysztof/dev/projects/spritesheet.js/test/fixtures/500x500.jpg" x="0" y="0" width="500" height="500"/>

</TextureAtlas>
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
119 changes: 119 additions & 0 deletions test/generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
var generator = require('../lib/generator');
var expect = require('expect.js');
var fs = require('fs');


describe('generator', function () {

describe('getImagesSizes', function () {
it('should return image sizes', function (done) {
var FILES = [
{name: __dirname + '/fixtures/50x50.jpg'},
{name: __dirname + '/fixtures/100x100.jpg'},
{name: __dirname + '/fixtures/200x200.jpg'},
{name: __dirname + '/fixtures/500x500.jpg'}
];

generator.getImagesSizes(FILES, function (err, files) {
expect(err).to.be(null);

expect(files[0].width).to.equal(50);
expect(files[0].height).to.equal(50);

expect(files[1].width).to.equal(100);
expect(files[1].height).to.equal(100);

expect(files[2].width).to.equal(200);
expect(files[2].height).to.equal(200);

expect(files[3].width).to.equal(500);
expect(files[3].height).to.equal(500);

done();
});
});
});

describe('determineCanvasSize', function () {
var FILES = [
{name: __dirname + '/fixtures/50x50.jpg', width: 50, height: 50},
{name: __dirname + '/fixtures/100x100.jpg', width: 100, height: 100},
{name: __dirname + '/fixtures/200x200.jpg', width: 200, height: 200},
{name: __dirname + '/fixtures/500x500.jpg', width: 500, height: 500}
];

it('should return square canvas', function (done) {
var options = {square: true, powerOfTwo: false};
generator.determineCanvasSize(FILES, options, function (err) {
expect(err).to.be(null);
expect(options.width).to.equal(options.height);

done();
});
});

it('should return square canvas', function (done) {
var options = {square: false, powerOfTwo: false};
generator.determineCanvasSize(FILES, options, function (err) {
expect(err).to.be(null);
expect(options.width).not.to.equal(options.height);
done();
});
});

it('should return power of two', function (done) {
var options = {square: false, powerOfTwo: true};
generator.determineCanvasSize(FILES, options, function (err) {
expect(err).to.be(null);
expect(options.width).to.equal(1024);
expect(options.height).to.equal(512);
done();
});
});

});

describe('generateImage', function () {
var FILES = [
{name: __dirname + '/fixtures/50x50.jpg', width: 50, height: 50, x: 0, y: 0},
{name: __dirname + '/fixtures/100x100.jpg', width: 100, height: 100, x: 0, y: 0},
{name: __dirname + '/fixtures/200x200.jpg', width: 200, height: 200, x: 0, y: 0},
{name: __dirname + '/fixtures/500x500.jpg', width: 500, height: 500, x: 0, y: 0}
];

it('should generate image file', function (done) {
var options = {width: 100, height: 100, path: __dirname + '/', imageFile: 'test.png'};
generator.generateImage(FILES, options, function (err) {
expect(err).to.be(null);
expect(fs.existsSync(__dirname + '/test.png')).to.be.ok();
done();
});
});

after(function () {
fs.unlinkSync(__dirname + '/test.png');
});
});

describe('generateData', function () {
var FILES = [
{name: __dirname + '/fixtures/50x50.jpg', width: 50, height: 50, x: 0, y: 0},
{name: __dirname + '/fixtures/100x100.jpg', width: 100, height: 100, x: 0, y: 0},
{name: __dirname + '/fixtures/200x200.jpg', width: 200, height: 200, x: 0, y: 0},
{name: __dirname + '/fixtures/500x500.jpg', width: 500, height: 500, x: 0, y: 0}
];

it('should generate data file', function (done) {
var options = {path: __dirname + '/', dataFile: 'test.xml'};
generator.generateData(FILES, options, function (err) {
expect(err).to.be(null);
expect(fs.existsSync(__dirname + '/test.xml')).to.be.ok();
done();
});
});

after(function () {
fs.unlinkSync(__dirname + '/test.xml');
});
});
});
30 changes: 30 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
var spritesheet = require('../index');
var assert = require('assert');
var expect = require('expect.js');
var fs = require('fs');

describe('spritesheet.js', function () {

it('should generate xml file', function (done) {
spritesheet([__dirname + '/fixtures/100x100.jpg'], {name: 'test', path: __dirname}, function (err) {
expect(err).to.be(null);
expect(fs.existsSync(__dirname + '/test.xml')).to.be.ok();
done();
});
});

it('should generate png file', function (done) {
spritesheet([__dirname + '/fixtures/100x100.jpg'], {name: 'test', path: __dirname}, function (err) {
expect(err).to.be(null);
expect(fs.existsSync(__dirname + '/test.png')).to.be.ok();
done();
});
});

after(function () {
fs.unlinkSync(__dirname + '/test.xml');
fs.unlinkSync(__dirname + '/test.png');
});

});

Loading

0 comments on commit 74bbdf9

Please sign in to comment.