Link to home
Start Free TrialLog in
Avatar of Crazy Horse
Crazy HorseFlag for South Africa

asked on

How to resize/compress image before uploading to cloud storage

So, I have deployed what I have done on my project so far to Heroku only to discover that that any images you upload to their server are deleted periodically! Not super helpful.

https://help.heroku.com/K1PPS2WM/why-are-my-file-uploads-missing-deleted

So, that means I have to either store the images in the database which I don't want to do, or upload to a cloud server. Before setting this up, I was using sharp to resize and compress the uploaded image. So, I uploaded the file into memory, resized/compressed it and then wrote it to a new file. I am uploading to google cloud storage.

I have the upload to the cloud working but it is uploading the original image, not the resized one. I think that it is because the cloud upload isn't uploading the one from memory but rather the original uploaded file.

This is the route:

router.post(
  "/",
  heroController.uploadUserPhoto,
  heroController.resizeUserPhoto,
  heroController.sendUploadToGCS,
  heroController.updateHeroImg
); 

Open in new window


Controllers

// save image to memory instead of to disk
const multerStorage = multer.memoryStorage();

const upload = multer({
  storage: multerStorage,
  fileFilter: multerFilter
});

// upload the image
exports.uploadUserPhoto = upload.single("bgImg");

//resize and compress image
exports.resizeUserPhoto = (req, res, next) => {
  if (!req.file) return next();

  req.file.filename = `hero-${Date.now()}.jpeg`;

  // get the image from memory
  sharp(req.file.buffer)
    .resize(1800, 948, {
      fit: sharp.fit.outside
    })
    .toFormat("jpeg")
    .jpeg({ quality: 80 })
    .toFile(`public/img/${req.file.filename}`);

  next();
};

Open in new window


const gc = new Storage({
  keyFilename: path.join(__dirname, "../someFile.json"),
  projectId: "something-here-123456"
});

const bucket = gc.bucket("myBucket");

function getPublicUrl(filename) {
  return `https://storage.googleapis.com/something-here-123456/${filename}`;
}

exports.sendUploadToGCS = (req, res, next) => {
  if (!req.file) {
    return next();
  }

  const gcsname = req.file.filename;
  const file = bucket.file(gcsname);

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

  stream.on("error", err => {
    req.file.cloudStorageError = err;
    next(err);
  });

  stream.on("finish", () => {
    req.file.cloudStorageObject = gcsname;
    file.makePublic().then(() => {
      req.file.cloudStoragePublicUrl = getPublicUrl(gcsname);
      next();
    });
  });

  stream.end(req.file.buffer);
};

Open in new window

Avatar of Kimputer
Kimputer

I don't think I have enough code to look at.
But besides that, why do you need to resize the pictures? Saving to Google Photos, means UNLIMITED FREE storage. (You're saving to Google Drive/Storage, this counts to your normal GMail storage limit)
Avatar of Crazy Horse

ASKER

I want to compress it for the frontend user. They should't have to download a 3.1mb image for a banner image. So, I want to compress it so they only have to download say 500kb instead.
OK please post the rest of the code you have.
Which code are you looking for? That is all the code that handles the upload. It just needs to be changed to upload the resized image instead of the original image.
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.