Sorry about digging up the old thread. After looking at that I went poking around the tests where I found "Composite three transparent PNGs into one".
What I was hoping to do was be able to chain overlayWith together like this:
sharp(layer1)
.overlayWith(layer2)
.overlayWith(layer3)
etc. as necessary.
From what I can tell though, I need to nest them in callbacks like in the test?
Essentially what I am dealing with is a dynamic number of image layers that can be composited into a single image. Each layer file has the same dimension as well as an alpha channel.
The layer stack goes something like this:
• color layer
• accent layer (0-n)
• shading
• highlight
• lineart
There can be other layers as well, but that's the most basic version.
Is there a way to achieve what I'm looking for without the callback hell?
Hello, given all the images are the same dimension, I'd probably use a Promises and raw pixel data approach for this, something like the following (untested):
const options = {
raw: {
width: 200,
height: 100,
channels: 4
}
};
const base = sharp('color.png').raw().toBuffer();
const composite = [
'accent0.png',
'accent1.png',
'accentn.png',
'shading.png',
'highlight.png',
'lineart.png'
].reduce( function(input, overlay) {
return input.then( function(data) {
return sharp(data, options).overlayWith(overlay).raw().toBuffer();
});
}, base);
composite.then(function(data) {
// data contains the multi-composited image as raw pixel data
});
I love the way this is setup. It definitely looks like what I'm trying to achieve!
Right now I'm getting:
throw new Error('Unsupported input ' + typeof input);
I've been messing about with what you wrote above, trying to piece it all together. I'm fairly new to the Node environment so I spent some time this evening reading over handling the filesystem / buffered data / etc.
I tried removing the toBuffer() from the lines "const base = ..." and "return sharp(input, opt...)", thinking maybe I could just pass back the raw data since it didn't like the Promise it got back from toBuffer(). It didn't like the input format for that either, though.
I appreciate you taking the time to assist!
These are sample images I'm trying (the only difference being the width and height set to 400 from your script above):
accent0.png

accent1.png

color.png

highlight.png

lineart.png

shading.png

I've updated the code sample:
- return sharp(input, options).overlayWith(overlay).raw().toBuffer();
+ return input.then( function(data) {
+ return sharp(data, options).overlayWith(overlay).raw().toBuffer();
+ });
Perfect, very much appreciated!
i try it,down all source to demo,use this your code run fail.
(node:3832) UnhandledPromiseRejectionWarning: Error: Overlay image must have same dimensions or smaller
(node:3832) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:3832) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Most helpful comment
Hello, given all the images are the same dimension, I'd probably use a Promises and raw pixel data approach for this, something like the following (untested):