3

I tried to resize or compress an image before uploading to the google cloud storage. The upload works fine but the resizing does not seem to work.

Here is my code:

const uploadImage = async (file) => new Promise((resolve, reject) => {
    let { originalname, buffer } = file
    sharp(buffer)
        .resize(1800, 948)
        .toFormat("jpeg")
        .jpeg({ quality: 80 })
        .toBuffer()


    const blob = bucket.file(originalname.replace(/ /g, "_"))
    const blobStream = blob.createWriteStream({
        resumable: false
    })
    blobStream.on('finish', () => {
        const publicUrl = format(
            `https://storage.googleapis.com/${bucket.name}/${blob.name}`
        )
        resolve(publicUrl)
    }).on('error', () => {
            reject(`Unable to upload image, something went wrong`)
        })
        .end(buffer)
}) 
iLuvLogix
  • 5,920
  • 3
  • 26
  • 43
foka135
  • 167
  • 2
  • 13
  • 2
    `toBuffer()` seems to be returning a promise. Try adding async in the promise `new Promise(async (resolve, reject)` and await in here `let { originalname, buffer } = await file...` – Dharmaraj Aug 25 '21 at 13:13

3 Answers3

3

I ran into the same issue with a project I was working on. After lots of trial and error I found the following solution. It might not be the most elegant, but it worked for me.

In my upload route function I created a new thumbnail image object with the original file values and passed it as the file parameter to the uploadFile function for google cloud storage.

Inside my upload image route function:

const file = req.file;

const thumbnail = {
  fieldname: file.fieldname,
  originalname: `thumbnail_${file.originalname}`,
  encoding: file.encoding,
  mimetype: file.mimetype,
  buffer: await sharp(file.buffer).resize({ width: 150 }).toBuffer()
}

const uploadThumbnail = await uploadFile(thumbnail);

My google cloud storage upload file function:

const uploadFile = async (file) => new Promise((resolve, reject) => {

  const gcsname = file.originalname;
  const bucketFile = bucket.file(gcsname);

  const stream = bucketFile.createWriteStream({
    resumable: false,
    metadata: {
      contentType: file.mimetype
    }
  });

  stream.on('error', (err) => {
    reject(err);
  });

  stream.on('finish', (res) => {
    resolve({ 
      name: gcsname
    });
  });

  stream.end(file.buffer);
});
L1C4U5E
  • 31
  • 3
0

I think the problem is with toFormat(). That function does not exist in the Docs. Can you try to remove it and check if it would work?

sharp(buffer)
  .resize(1800, 948)
  .jpeg({ quality: 80 })
  .toBuffer()
NeNaD
  • 18,172
  • 8
  • 47
  • 89
0

Modify the metadata once you have finished uploading the image.

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { log } from "firebase-functions/logger";
import * as sharp from "sharp";

export const uploadFile = functions.https.onCall(async (data, context) => {
  const bytes = data.imageData;

  const bucket = admin.storage().bucket();

  const buffer = Buffer.from(bytes, "base64");

  const bufferSharp = await sharp(buffer)
    .png()
    .resize({ width: 500 })
    .toBuffer();

  const nombre = "IMAGE_NAME.png";

  const fileName = `img/${nombre}.png`;
  const fileUpload = bucket.file(fileName);

  const uploadStream = fileUpload.createWriteStream();

  uploadStream.on("error", async (err) => {
    log("Error uploading image", err);

    throw new functions.https.HttpsError("unknown", "Error uploading image");
  });

  uploadStream.on("finish", async () => {
    await fileUpload.setMetadata({ contentType: "image/png" });

    log("Upload success");
  });

  uploadStream.end(bufferSharp);
});

edalvb
  • 581
  • 6
  • 7