So, anytime you have multiple async operations to coordinate in some way, I immediately want to go to promises. And, the best way to use promises to coordinate a number of async operations is to make each async operation return a promise. The lowest level async operation you show is fs.readFile(). Since I use the Bluebird promise library, it has a function for "promisifying" a whole module's worth of async functions.

This will create new parallel methods on the fs object with an "Async" suffix that return promises instead of use straight callbacks. So, there will be an fs.readFileAsync() that returns a promise. You can read more about Bluebird's promisification here.

So, now you can make a function that gets an image fairly simply and returns a promise whose value is the data from the image:

Though, you will quickly find that once you start using promises, you want to use them for all async operations so you'll be "promisifying" lots of things and having a library or at least a generic function that will do that for you will save lots of time.