Convert image format on Cloud Storage with Cloud Functions and Sharp does not work

1.1k Views Asked by At

When uploading an image to Firebase Cloud Storage, I want to resize and convert the image format to webp. So I created a trigger with Cloud Function. To do this, I am using Node.js Sharp library.

The Cloud Function resizes the image correctly, but it always keeps me the original format.

This is the code for the conversion and resize:

function resize(originalFile, resizedFile, size) {
  let height, width;
  if (size.indexOf(",") !== -1) {
    [width, height] = size.split(",");
  } else if (size.indexOf("x") !== -1) {
    [width, height] = size.split("x");
  } else {
    throw new Error("height and width are not delimited by a ',' or a 'x'");
  }
  return sharp(originalFile)
    .rotate()
    .toFormat("webp", {
      quality: 80,
      force: true
    })
    .resize(parseInt(width, 10), parseInt(height, 10), {
      fit: "inside",
      withoutEnlargement: true,
    }).toFile(resizedFile);
}

Running on a node.js project locally, it works fine.

UPDATE

I'm using Sharp 0.26.1, I also tried previous versions as suggested, but nothing has changed.

I tried this too, using the fs-extra library to write the file, but the result is still the same: resize and compression work correctly, while format conversion does not.

async function resize(originalFile, resizedFile, size) {
  let height, width;
  if (size.indexOf(",") !== -1) {
    [width, height] = size.split(",");
  }
  else if (size.indexOf("x") !== -1) {
    [width, height] = size.split("x");
  }
  else {
    throw new Error("height and width are not delimited by a ',' or a 'x'");
  }


  const data = await sharp(originalFile)
    .rotate()
    .toFormat("webp")
    .resize(parseInt(width, 10), parseInt(height, 10), {
      fit: "inside",
      withoutEnlargement: true,
    })
    .webp({
      quality: 80,
      force: true
    })
    //.toFile(resizedFile);
    .toBuffer();
    fs.writeFileSync(resizedFile, data);

}

Again, launching the code locally, it works fine. (When I say "locally" I mean on a node.js project. It is not possible to test this Cloud Function locally, because there is no official Cloud Storage local emulator)

2

There are 2 best solutions below

12
On

Instead of using only toFormat() try using it followed by the webp() call, like this:

return sharp(originalFile)
    .rotate()
    .resize(parseInt(width, 10), parseInt(height, 10), {
        fit: "inside",
        withoutEnlargement: true,
    })
    .toFormat("webp")
    .webp({
        quality: 80,
        force: true
    });
    .toFile(resizedFile);

This should make it work.

1
On

I have been battling with this for hours and this is what finally worked for me. Make sure the mimetype you are setting with the upload header you are using for uploading to AWS/Azure/Digital Ocean is 'image/webp'