I am ordering images by a score value calculated by the getImageScore
method, which is wrapped in a promise, as it takes quite some time to load the pixels it has to work with. I observed that the promises get blocked, never being finished. This was the initial whole program:
const fs = require('fs');
const { resolve } = require('path');
const { reject } = require('q');
const { Console } = require('console');
const gm = require('gm').subClass({imageMagick: true});
const PNG = require("pngjs").PNG;
let pathToFolder = '/home/eugen/Pictures/wallpapers1';
let pathToImage = '';
let promiseImageScore = new Promise((resolve, reject) => {
getImageScore(resolve, reject);
});
function getImageScore(resolve, reject) {
console.log('entered this promise....');
let img = gm(pathToImage);
// Get the PNG buffer
img.toBuffer("PNG", (err, buff) => {
if (err) return reject(err);
console.log('got buffer...');
// Get the image size
img.size((err, size) => {
if (err) {
console.log(err);
return reject(err);
}
console.log('got image size...');
// Parse the PNG buffer
let str = new PNG();
str.end(buff);
// After it's parsed...
str.on("parsed", buffer => {
// Get the pixels from the image
let idx, score = 0, rgb = {r: 0, g: 0, b: 0};
for (let y = 0; y < size.height; y++)
for (let x = 0; x < size.width; x++) {
idx = (size.width * y + x) << 2;
rgb.r = buffer[idx];
rgb.g = buffer[idx + 1];
rgb.b = buffer[idx + 2];
score += (rgb.r + rgb.g + rgb.b) / 765;
}
console.log('one promise finished...');
return resolve(score / (size.height * size.width));
});
str.on("error", e => {
return reject(e);
});
});
});
}
// see which images are to be found in the specificd directory
fs.readdir(pathToFolder, function (err, files) {
if (err) return console.log('Unable to scan directory: ' + err);
console.log('files in directory:\n');
files.forEach(function (file) {
pathToImage = pathToFolder + '/' + file;
//showImageScore();
promiseImageScore
.then(imageScore => {
console.log(file + ' has a score of ' + imageScore);
})
.catch(e => {
throw e;
})
});
});
Running the above code would result in this output:
entered this promise....
files in directory:
got buffer...
After logging the got buffer
message, the program would just run continuously... I saw that, by modifying the way I'm appealing images, I would finally get the got image size
log in the console. Therefore, here is the way I modified the getImageScore
method:
function getImageScore(resolve, reject) {
console.log('entered this promise....');
//let img = gm(pathToImage);
// Get the PNG buffer
//img.toBuffer("PNG", (err, buff) => {
gm(pathToImage).toBuffer("PNG", (err, buff) => {
if (err) return reject(err);
console.log('got buffer...');
// Get the image size
//img.size((err, size) => {
gm(pathToImage).size((err, size) => {
if (err) {
console.log(err);
return reject(err);
}
console.log('got image size...');
// Parse the PNG buffer
let str = new PNG();
console.log('created str...');
str.end(buff);
console.log('got str...');
// After it's parsed...
str.on("parsed", buffer => {
// Get the pixels from the image
let idx, score = 0, rgb = {r: 0, g: 0, b: 0};
for (let y = 0; y < size.height; y++)
for (let x = 0; x < size.width; x++) {
idx = (size.width * y + x) << 2;
rgb.r = buffer[idx];
rgb.g = buffer[idx + 1];
rgb.b = buffer[idx + 2];
score += (rgb.r + rgb.g + rgb.b) / 765;
}
console.log('one promised finished...');
return resolve(score / (size.height * size.width));
});
str.on("error", e => {
return reject(e);
});
});
});
}
After making these changes, I am getting the following output in the console:
entered this promise....
files in directory:
got buffer...
got image size...
created str...
events.js:174
throw er; // Unhandled 'error' event
^
Error: Invalid file signature
at module.exports.Parser._parseSignature (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/parser.js:53:18)
at module.exports.ChunkStream._processRead (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:174:13)
at module.exports.ChunkStream._process (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:193:14)
at module.exports.ChunkStream.write (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:61:8)
at module.exports.ChunkStream.end (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:74:10)
at exports.PNG.PNG.end (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/png.js:98:16)
at gm.size (/home/eugen/Documents/scripts/sort_pictures_by_brightness/index.js:34:11)
at gm.emit (events.js:198:13)
at gm.<anonymous> (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/getters.js:82:14)
at cb (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:322:16)
Emitted 'error' event at:
at module.exports.emit (events.js:198:13)
at module.exports.ChunkStream._process (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:207:10)
at module.exports.ChunkStream.write (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:61:8)
[... lines matching original stack trace ...]
at cb (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:322:16)
at ChildProcess.onExit (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:305:9)
From seeing the output, we can say that the str.end(buff);
line has some kind of problem, as the program never outputs the got str
log. This problem didn't seem to exist, before making the changes I made in the getImageScore
method. Firstly, I don't really understand why loading an image in a local object would be a problem that would cause the code to act unexpectedly. Secondly, modifying the way an image is loaded should not alter the end
method from the pngjs
library. Can someone explain what is actually happening here and how can this issue be fixed?
Fortunately, someone from Facebook (Iulian Popescu) told me that files.forEach
doesn't wait for the promises to finish, therefore they get blocked. I managed to solve this situation, by adding more promises. For sample, one of the promises reads all the data. After reading all the data and saving it in some global variables, the other promises would get executed, in the right order. If you'd like to actually see the implementation of the solution I'm talking about, you can check it out on my GitHub: https://github.com/tomaAlex/darkImageClassifier/blob/master/index.js