2

I have the task of stacking several pngs one on top of another and exporting it as one png. The images do not have the same size, however they do not need to be resized, just cropped to the available canvas.

The images come from the file system and are sent as a buffer. There may be somewhere between 8 and 30 images.

My tests have been with 10 images, and I have compared it with node-canvas which takes less than 50% of the time that Sharp does. I think one problem with Sharp is that I have to make and extract operation before compositing.

This is my code running with Sharp, which takes ~600ms with 10 images:

export const renderComponentsSHARP = async ( layers  )=>{

    const images = [];

    for(let i=0; i<layers.length; i++){
        const layer = sharp(layers[i]));
        const meta =  await layer.metadata();
        if(meta.height > AVATAR_SIZE.height || meta.width > AVATAR_SIZE.width)
            layer.extract({ top:0, left:0, ...AVATAR_SIZE });
        images.push({input:await layer.toBuffer()});
    }

    return sharp({
        create: {
            ...AVATAR_SIZE,
            channels: 4,
            background: { r: 0, g: 0, b: 0, alpha: 0 }
        }})
        .composite(images)
        .png()
        .toBuffer();
};

This is my code running with canvas, which takes ~280ms:

export const renderComponentsCANVAS = async ( layers )=>{

    const canvas = createCanvas(AVATAR_SIZE.width, AVATAR_SIZE.height);
    const ctx = canvas.getContext('2d');

    const images = await Promise.all(layers.map( layer=>loadImage(layer)));

    images.forEach(image=>{
        ctx.drawImage(image, 0, 0);
    });

    return canvas.toBuffer();
};

Am I doing something wrong with sharp? Or is it not the tool for this job?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Mark E
  • 3,403
  • 2
  • 22
  • 36
  • With canvas you are reading all images at the same time, while with sharp you are doing it one by one. Can you try `Promise.all()` with sharp? – thammada.ts Jun 17 '20 at 16:57
  • You're right. I thought it would make not much of a difference because of the single threaded nature of node. But it's definitely worth a try. I'll update with that – Mark E Jun 17 '20 at 22:57
  • sharp is [powered by](https://sharp.pixelplumbing.com/#fast) cpp libraries under the hood, so it's not limited by the single thread of node. Tip: you can even specify [concurrency](https://sharp.pixelplumbing.com/api-utility#concurrency) which already has a decent default as the number of cpu cores – thammada.ts Jun 17 '20 at 23:13
  • Also, try `layer.raw().toBuffer()` instead of `layer.toBuffer()` – thammada.ts Jun 17 '20 at 23:23

0 Answers0