Image Compression with Node.js

Francisco Mendes - May 15 '21 - - Dev Community

Currently, I feel that the market is increasingly oriented towards the use of third-party services to make part of our pipeline. One of the most common is to compress images.

However, I will show that with a simple Express.js api we can upload an image, change the Mime Type and still decrease its size.

I don't think I need to talk about Express.js because everyone who uses Node.js has used this framework at some point. Today I'm going to focus on multer and sharp.

Nowadays uploading images is one of the most basic operations of all applications. Multer is a middleware for handling multipart/form-data that is mainly used to upload files. By combining Express.js with multer, we will be able to easily implement the file upload feature.

Sharp is a module for Node.js to convert images of the most diverse formats and varied dimensions to a smaller size, without having to worry about the color space, channels and alpha transparency, because all of these are treated correctly.

The image format that we are going to use in this example is WebP, which offers compression greater than png and jpg, which helps to load web pages more quickly. And it is supported by all browsers.

How to use

First we will create a new project in Node.js and then we will install the necessary dependencies:

# We will use the default values.
npm init -y

# Necessary dependencies.
npm install express multer sharp
Enter fullscreen mode Exit fullscreen mode

After that we will create a simple api:

const express = require("express");

const app = express();

app.get("/", (req, res) => {
 return res.json({ message: "Hello world 🔥🇵🇹" });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Once the application is working properly, we will move on to configuring multer. If you visited the multer documentation, I believe you saw that we can save the images in two ways: DiskStorage or MemoryStorage.

In this case, we will use MemoryStorage, because we want to have access to the buffer that is made available by multer. And we will also use the static function of Express.js so that later we can serve our images.

const express = require("express");
const multer = require("multer");

const app = express();
const storage = multer.memoryStorage();
const upload = multer({ storage });

app.use(express.static("./uploads"));

app.get("/", (req, res) => {
 return res.json({ message: "Hello world 🔥🇵🇹" });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

After that, we will create an endpoint to make the http request with the POST verb, however we will add the middleware upload and we will only upload a single file which we will call “picture”.

app.post("/", upload.single("picture"), async (req, res) => {
 // The logic goes here.
});
Enter fullscreen mode Exit fullscreen mode

The next step is to check if the "uploads" folder exists in our workspace, if it doesn't, we will want Node.js to create it for us. For that we need to have access to the file system, so we will use the fs module.

app.post("/", upload.single("picture"), async (req, res) => {
 fs.access("./uploads", (error) => {
   if (error) {
     fs.mkdirSync("./uploads");
   }
 });
 // Even more logic goes here.
});
Enter fullscreen mode Exit fullscreen mode

Now we can start working with sharp, but first I like to create a random string to have it before the name of the image, this is because several images can have the same name and so it is better to be careful. In this case I am using a timestamp (to make it easier to understand) but the ideal was to have a random string of 16 characters. Then we will access the buffer and the originalname of the image thanks to multer.

app.post("/", upload.single("picture"), async (req, res) => {
 fs.access("./uploads", (error) => {
   if (error) {
     fs.mkdirSync("./uploads");
   }
 });
 const { buffer, originalname } = req.file;
 const timestamp = new Date().toISOString();
 const ref = `${timestamp}-${originalname}.webp`;
 // Even more logic goes here.
});
Enter fullscreen mode Exit fullscreen mode

Now just pass the image buffer to sharp and then configure the desired quality, the format we want and where the file goes. In this case, I will want the file in the “uploads” folder with the name we have assigned (the ref variable).

app.post("/", upload.single("picture"), async (req, res) => {
 fs.access("./uploads", (error) => {
   if (error) {
     fs.mkdirSync("./uploads");
   }
 });
 const { buffer, originalname } = req.file;
 const timestamp = new Date().toISOString();
 const ref = `${timestamp}-${originalname}.webp`;
 await sharp(buffer)
   .webp({ quality: 20 })
   .toFile("./uploads/" + ref);
 // Almost finished...
});
Enter fullscreen mode Exit fullscreen mode

Last but not least, I will create a variable called link that will be the url with which we will be able to view our new image in the browser.

The final code should be as follows:

const express = require("express");
const multer = require("multer");
const sharp = require("sharp");
const fs = require("fs");

const app = express();
const storage = multer.memoryStorage();
const upload = multer({ storage });

app.use(express.static("./uploads"));

app.get("/", (req, res) => {
  return res.json({ message: "Hello world 🔥🇵🇹" });
});

app.post("/", upload.single("picture"), async (req, res) => {
  fs.access("./uploads", (error) => {
    if (error) {
      fs.mkdirSync("./uploads");
    }
  });
  const { buffer, originalname } = req.file;
  const timestamp = new Date().toISOString();
  const ref = `${timestamp}-${originalname}.webp`;
  await sharp(buffer)
    .webp({ quality: 20 })
    .toFile("./uploads/" + ref);
  const link = `http://localhost:3000/${ref}`;
  return res.json({ link });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Just use your favorite http client (in this case I used Insomnia) and don't forget to send the image with multipart/form-data and the name of the field must be “picture” and the type is file.

Like this:

screenshot

What about you?

What is your favorite image format?

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player