-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
139 lines (117 loc) · 4.78 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"use strict";
const fs = require('fs');
const process = require('process');
const path = require('path');
const imglib = require('images');
let map = { frames: [] };
let imgHTML = [];
// get the sequences (directories signifying sequences)
function getSequences(sequences) {
return new Promise((resolve, reject) => {
fs.readdir(sequences, (err, files) => {
if(err) return reject(err);
resolve(files.filter(file => fs.statSync(path.join(sequences, file)).isDirectory()));
})
})
}
// generate all sequences
function generateAll (sequences) {
return new Promise((resolve, reject) => {
sequences.reduce((p, seq, i, arr) => {
return p.then(() => generateFlick(seq));
}, Promise.resolve())
.then(resolve);
})
}
// generate flick for each sequence
function generateFlick (seq) {
return new Promise((resolve, reject) => {
console.log(seq);
getFilenames(seq) // get all the files in the target directory
.then(fileNames => fileNames.filter((f, i) => /.jpg/.test(f))) // get the images of the sequence
.then(imageNames => imageNames.sort()) // sort them alpabetically
.then(sortedImageNames => sortedImageNames.map(s => imglib(`sequences/${seq}/` + s))) // get an array of image objects from the filenames
.then(images => createSprite(images, seq)) // create the sprite
.catch(e => console.log('Error creating sprite. Are the folders empty?'))
.then(global.gc) // free up resources for subsequent sprites
.then(resolve) // then resolve the promise
.catch(e => console.log('Garbage Collector failed to expose: %s', e))
})
}
// get the filenames of the individual frames
function getFilenames(seq) {
return new Promise((resolve, reject) => {
fs.readdir(`sequences/${seq}/`, function(err, files) {
if(err) return reject(err);
resolve(files);
})
})
}
// create sprites for each sequence
function createSprite(images, seq) {
let w = images[0].width(), // get the unit width of each image
h = images[0].height(), // get the unit height of each iamge
maxCols = Math.ceil(4096 / w), // get max columns per sprite
maxRows = Math.ceil(4096 / h), // get max rows per sprite
cols = maxCols, // as well as attributes for columns
rows = maxRows, // and rows
iteration = 0, // and the sequence iteration
sprite; // declare the empty sprite
let pos = { col: 0, row: 0 }; // remember position in the grid
let spritesNeeded = Math.ceil(images.length / (maxCols * maxRows));
let finalSprite = Math.ceil(images.length % (maxCols * maxRows));
images.forEach((img, i) => {
if(i % (maxCols * maxRows) === 0) { // if this is a new sprite
if(--spritesNeeded === 0) { // and this is the last sprite
cols = finalSprite < maxCols ? Math.ceil(finalSprite % maxCols) : maxCols; // calc cols in the sprite
rows = Math.ceil(finalSprite / cols); // and then the rows
}
pos = { col: 0, row: 0 }; // reset position in the grid
sprite = imglib(cols * w, rows * h); // create the sprite
}
map.frames.push({src: `${seq}_${iteration}.sprite.jpg`, x: w * pos.col, y: h * pos.row }); // add this frame to the animation frames object
sprite.draw(img, w * pos.col, h * pos.row); // draw this image to the sprite
if (pos.col + 1 > cols - 1) { // if we're at the end of the row
pos.row++; // move to the next row
pos.col = 0; // reset to the first column
}
else {
pos.col++; // otherwise just move to the next column
}
if((i + 1) % (maxCols * maxRows) === 0 || i === images.length - 1) {
console.log(`saving sprite: ${seq}_${iteration}.sprite.jpg`);
imgHTML.push(`<img class="sprite" src="flicker/${seq}_${iteration}.sprite.jpg" alt="${seq}"/>`);
sprite.save(`flicker/${seq}_${iteration}.sprite.jpg`);
iteration++;
}
})
}
// save the JSON coordinate map
function saveMap() {
return new Promise((resolve, reject) => {
fs.writeFile('flicker/flicker_map.json', JSON.stringify(map, null), err => { // write the flick to a file
if (err) return reject(err); // reject the promise on error
console.log('Succesfully saved JSON coordinate map');
resolve(); // otherwise resolve it
})
})
}
// save a list of the images in HTML format
function saveImgHTML() {
return new Promise((resolve, reject) => {
let html = imgHTML.join('\n');
fs.writeFile('flicker/flicker_imgHTML.html', html, err => { // write the img html to a file
if (err) return reject(err); // reject the promise on error
console.log('Succesfully saved img HTML template');
resolve(); // otherwise resolve it
})
})
}
// initialise the process
(function init(){
getSequences('sequences/') // get every sequence
.then(sequences => new Promise(resolve => generateAll(sequences).then(resolve))) // generate the flick with each sequence
.then(saveMap) // save the coordinate map
.then(saveImgHTML) // save the img HTML template
.catch(e => console.log(e)) // log any errors if they occur
})();