I once wrote a script to build a texture atlas from a set of images. The details can be found here:
http://www.gamedev.net/blog/863/entry-2261127-automatically-generating-sprites-for-a-space-shooter/.
The script used the
binpacking library pack the sprites tightly, and then used
gm and
imagemagick to composite the sprites into the final image.
It’s trivial to wrap the binpacker into a simple command line program:
// binpack.js
var readline = require('readline');
var binpacking = require('binpacking');
var boxes = [];
readline.createInterface({
input: process.stdin,
})
.on('line', (line) => {
// transform lines from stdin into boxes
var arr = /^(\d+)\s+(\d+)\s+(.+?)$/.exec(line);
if ( arr ) {
boxes.push({
w: +arr[1],
h: +arr[2],
tag: arr[3],
});
}
else {
process.stderr.write("Failed to process: '"+line+"'\n");
}
})
.on('close', () => {
// sort boxes, largest to smallest widths then heights.
boxes.sort((a,b) => {
if ( a.w < b.w ) return 1;
if ( a.w > b.w ) return -1;
if ( a.h < b.h ) return 1;
if ( a.h > b.h ) return -1;
return 0;
});
// bin-pack!
var packer = new binpacking.GrowingPacker;
packer.fit(boxes);
// output final atlas size and sprite locations
process.stdout.write(packer.root.w+'\t'+packer.root.h+'\n');
boxes.forEach((box) => {
var f = box.fit;
process.stdout.write([f.x, f.y, f.w, f.h, box.tag].join('\t')+'\n');
});
});
Then try it out:
> # generate a set of twenty random images:
> $set = 1..20 |% {
$rand = new-object Random;
$gen = {$rand.Next(64,256);};
} {
"$(&$gen) $(&$gen) path/to/image$_.png"
}
> # width height and image
> $set
127 221 path/to/image1.png
166 238 path/to/image2.png
204 69 path/to/image3.png
197 83 path/to/image4.png
100 115 path/to/image5.png
236 192 path/to/image6.png
97 139 path/to/image7.png
122 74 path/to/image8.png
127 168 path/to/image9.png
203 94 path/to/image10.png
80 212 path/to/image11.png
168 161 path/to/image12.png
64 79 path/to/image13.png
253 179 path/to/image14.png
129 253 path/to/image15.png
180 114 path/to/image16.png
250 208 path/to/image17.png
223 110 path/to/image18.png
247 102 path/to/image19.png
243 225 path/to/image20.png
> # (assuming script has npm dependencies installed)
> # feed into the script
> $set | node binpack.js
1001 848
0 0 253 179 path/to/image14.png
0 179 253 208 path/to/image17.png
253 0 247 387 path/to/image19.png
253 102 247 285 path/to/image20.png
500 0 236 387 path/to/image6.png
500 192 236 195 path/to/image18.png
500 302 236 85 path/to/image3.png
0 387 736 94 path/to/image10.png
203 387 533 94 path/to/image4.png
0 481 736 114 path/to/image16.png
736 0 168 595 path/to/image12.png
736 161 168 434 path/to/image2.png
0 595 904 253 path/to/image15.png
129 595 775 253 path/to/image1.png
736 399 168 196 path/to/image9.png
400 387 336 83 path/to/image8.png
256 595 648 221 path/to/image5.png
904 0 97 848 path/to/image7.png
904 139 97 709 path/to/image11.png
904 351 97 497 path/to/image13.png
The output here could then be fed into
imagemagick to render the atlas.