Search code examples
node.jsnode-archiver

Resizing and zipping image streams using archiver and sharp


I'm trying to download some images, resize them, zip them, and serve from an endpoint using streams. I'm using sharp for the resizing and archiver for the zipping. I can get these packages to work on their own but not together.

Here's some example code:

const Hapi = require('hapi');
const archiver = require('archiver');
const sharp = require('sharp');
const request = require('request');

function foo() {
  return new Promise((resolve, reject) => {
    const imageStreams = [request('https://i.sstatic.net/tKsDb.png'), request('https://i.sstatic.net/EdUwb.png'), request('https://i.sstatic.net/5d55j.png')]

    const zip = archiver('zip');
    zip.on('error', e => console.log('zip error: ', e.message));
    zip.on('entry', entry => console.log('appended ', entry.name));

    resolve(zip);

    process.nextTick(() => {
      console.log('number of streams: ', imageStreams.length);

      imageStreams.map((stream, j) => {
        const resize = sharp().resize(100, 100);

        return stream.pipe(resize);
      })
      .forEach((resizedImageStream, i) => {
        console.log('appending ', i, ' to zip');
        zip.append(resizedImageStream, { name: `${i}.png` });
      });

      console.log('finalizing zip');
      zip.finalize();
    });
  });
}

const server = new Hapi.Server();
server.connection({port: 3000});

server.route({
  method: 'GET',
  path: '/',
  handler: (request, reply) => {
    foo().then(zip => reply(zip));
  }
})
server.start();

Run it with: npm init --yes && npm install hapi archiver sharp request && node index.js

This will create an endpoint at http://localhost:3000 which will fail to stream the zip file to the response.

The following will each make the download work:

  • Removing the sharp transformation
  • Replacing sharp with imagemagick-stream
  • Only handling a single image, i.e. imageStreams.slice(0, 1)

But I can't get it to work with multiple images and resizing at the same time.


Solution

  • This turned out to be a bug in the sharp library, which has now been fixed here