Image Resizing In Node.Js For Memory Optimization And Better Application Performance.

  • Home
  • Uncategorized
  • Image Resizing In Node.Js For Memory Optimization And Better Application Performance.

In our Web app when we have a requirement as to display a particular image at a fixed size, even image size is too large we can load and display it from the front end since memory and time consumption will not be high, but what if we need to display some hundreds of users profile images at a fixed size in a list view and same images in grid view so in that case memory and time consumption will be more if we resize through the front end and display them.

So in this scenario, the best possible approach would be to resize the image at the server-side in the required sizes at the time of uploading.
For resizing images we can use available npms like sharp, gimp, and many more. Using sharp is the easiest way.
First, we need multer npm. Multer is a node.js middleware for handling multipart/form-data which is mostly used for uploading files.

var multer = require(‘multer’),
const uploadImage = [];
var storage = multer.diskStorage({
   destination: function (req, file, callback) {
   callback(null, ‘/upload/logo/’);
 },
 filename: function (req, file, callback) {
   if (file.originalname) {
     var p = file.originalname.lastIndexOf(‘.’);
     var ext = file.originalname.substring(p + 1);
     var firstName = file.originalname.substring(0, p + 1);
     var name = `${Date.now()}_ ${firstName}${ext}`;
   }
   uploadImage.push({ ‘name’: name });
   callback(null, name);
 }
});
var uploadLogo = multer({ storage: storage }).array(‘logo’);

Mongoose schema fields for uploading and resizing images in different sizes looks like this, if we want more different sizes we can add more fields.

logo: {
 data: {
   large: {
     type: Object
   },
   medium: {
     type: Object
   },
   small: {
     type: Object
   }
 },
 base64: {
   large: {
     type: String
   },
   medium: {
     type: String
   },
   small: {
     type: String
   }
 }
},

Here we are directly storing the image data so this is my mongoose schema fields. We can directly store the filenames and display them through the front end by providing the path of the images.

We need to import sharp npm since it is the fastest module for converting images into various formats like jpeg, png,webp, and other format images of various dimensions, apart from image resizing we can also perform operations such as rotation, extraction, and composition.

Here is our image resizing functionality. We need to create a sizeConfig object containing the required sizes data. We need to pass these sizes to sharp npm along with the original file path in a loop and store the resized images in the upload/logo folder.

var sharp = require(‘sharp’);
var sizeConfig = {
 ‘large’: { height: 640, width: 480 },
 ‘medium’: { height: 320, width: 240 },
 ‘small’: { height: 160, width: 120 }
};
const resizeImage = async (req, res) => {
 try {
   if (req.files && req.files[0] && req.files[0].originalname) {
     var p = req.files[0].originalname.lastIndexOf(‘.’);
     var ext = req.files[0].originalname.substring(p + 1);
     var firstName = req.files[0].originalname.substring(0, p + 1);
     var name = `${Date.now()}_ ${firstName}${ext}`;
     for (let size in sizeConfig) {
       let result = await sharp(req.files[0].path).resize(sizeConfig[size].height, sizeConfig[size].width).jpeg({ quality: 100 }).toFile(‘/upload/logo/’ +
        name);
       if (result) uploadImage[0][size] = name;
     }
   }
 }
 catch (err) {
   return res
     .send({
       errorCode: ‘9001’,
       errorMessage: err
     });
 }
}

We will be using the above resize image functionality in our main upload logo function.

Following is the main upload logo functionality where we need to call the above created resize image function and store the resized image data in our user document.Here we need to use fs npm to read the resized images and convert them to base64 format.

var fs = require(‘fs’),
exports.uploadLogo = (req, res) => {
uploadLogo(req, res, async function (err) {
 if (err) {
return res.json({ message: ‘–Error–‘ });
} else {
 if (req && req.files && req.files[0] && req.files[0].path) {
 await resizeImage(req, res);
if (req && req.query && req.query.id) {
 User.findById(req.query.id).exec(function (err, user) {
 if (err) {
  return res.send({ error: ‘OK’ });
 } else if (user) {
for (let size in sizeConfig) {
 //resized image data;
 let resizedPath = ‘/upload/logo/’ + uploadImage[0][size];
 user.logo.data[size] = fs.readFileSync(resizedPath);
  let base64 = fs.readFileSync(resizedPath).toString(‘base64’);
 while (base64 === ”) {
 base64 = fs.readFileSync(resizedPath).toString(‘base64’);
}
 user.logo.data[size] = fs.readFileSync(resizedPath);
user.logo.base64[size] = base64;
 }
user.save(function (err, result) {
 if (err) {
  return res.send({ error: ‘OK’ });
 } else {
 res.jsonp({ details: user });
  }
  });
} else {
 return res.send({ error: ‘OK’ });
 }
 });
} else {
 return res.send({ error: ‘OK’ });
 }
} else {
 res.jsonp({ details: {} });
 }
}
});
}

After storing the resized images in user documents we can empty the logo folder since we have already stored the resized image data.

If we opt to store just the resized images names we need to store the images in the logo folder and we need to do slight modifications in the mongoose schema and upload logo function and need to provide the path of the images at the time of displaying.

Leave A Comment

Your email address will not be published. Required fields are marked *