In this tutorial, I will show you how to upload & resize multiple images in Node.js using Express, Multer and Sharp.
Related Posts:
– How to upload multiple files in Node.js
– Upload/store images in MySQL using Node.js, Express & Multer
– Upload/store images in MongoDB using Node.js, Express & Multer
– Node.js Express File Upload Rest API example using Multer (static folder)
– Google Cloud Storage with Node.js: File Upload example
Fullstack:
– File Upload using Angular 8 and Node.js example
– File Upload using Angular 11 and Node.js example
– File Upload using Angular 12 and Node.js example
Contents
There is a couple of things to learn before we go to the practice part.
Uploading multiple images using Multer
Upload multiple images View
In HTML, we create a form with following elements:
action="/multiple-upload"
enctype="multipart/form-data"
multiple
input
<form
action="/multiple-upload"
method="POST"
enctype="multipart/form-data">
...
<input type="file" multiple>
...
</form>
Using Multer to upload multiple Images
Let’s configure multer and create some functions.
const multer = require("multer");
const multerStorage = multer.memoryStorage();
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith("image")) {
cb(null, true);
} else {
cb("Please upload only images.", false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
const uploadFiles = upload.array("images", 10); // limit to 10 images
const uploadImages = (req, res, next) => {
uploadFiles(req, res, err => {
if (err instanceof multer.MulterError) { // A Multer error occurred when uploading.
if (err.code === "LIMIT_UNEXPECTED_FILE") { // Too many images exceeding the allowed limit
// ...
}
} else if (err) {
// handle other errors
}
// Everything is ok.
next();
});
};
In the code above, we’ve done these steps:
– First, import multer
module.
– Next, configure multer
to store images in memory as a buffer so that we could then use it later by other processes (resize the images before saving them to disk).
– We also define a filter to only allow images to pass.
– Then use multer
object to create uploadFiles
function with the field images and the max count. The array of files will be stored in req.files
.
– We catch errors by calling the uploadFiles
middleware function, if there is no error, call next()
.
Resizing images using Sharp
Now we’re gonna process all of uploaded images (which are in memory).
const sharp = require("sharp");
const resizeImages = async (req, res, next) => {
if (!req.files) return next();
req.body.images = [];
await Promise.all(
req.files.map(async file => {
const newFilename = ...;
await sharp(file.buffer)
.resize(640, 320)
.toFormat("jpeg")
.jpeg({ quality: 90 })
.toFile(`upload/${newFilename}`);
req.body.images.push(newFilename);
})
);
next();
};
Let me explain the code.
– We import sharp
module.
– The resizeImages
will be an async function in that:
- We check if there are no images uploaded, move straight to the next middleware
- For each image, we return a
Promise
, we need all of thePromises
done before callingnext()
. So we get an array of all of thesePromises
usingarray.map()
then put it inPromise.all()
function. - We process every image in the
images
array usingresize()
method, then change the format (with file extension) tojpeg
with toFormat() and save it to disk usingtoFile()
method.
The Route Handler Functions
We write all middleware functions above in a Controller called upload
.
We use Express Router
to handle POST action to "/multiple-upload"
endpoint.
const express = require("express");
const router = express.Router();
const uploadController = require("./../controllers/upload");
let routes = app => {
...
router.post(
"/multiple-upload",
uploadController.uploadImages,
uploadController.resizeImages,
uploadController.getResult
);
return app.use("/", router);
};
module.exports = routes;
You can see that we insert uploadImages
and resizeImages
, then uploadController.getResult
. This is because we will process images before showing the result message.
Demo
Open browser for the app:
Choose some images to upload & resize:
Click on Submit button, if the process is successful, browser shows the uploaded images:
Check the upload folder, you can see the resized images:
If you choose the file without image format, or the images you want to upload exceeds the allowed amount, the browser will show the messages.
Practice: Upload & Resize multiple images with Node.js
Now I’m gonna show you how to build this Node.js application step by step.
Project Structure
This is our project structure:
– upload
: the folder for storing uploaded images.
– views/index.html
: contains HTML form for user to upload images.
– routes/web.js
: defines routes for endpoints that is called from views, use controllers to handle requests.
– controllers
:
home.js
returnsviews/index.html
upload.js
handles upload & resize multiple images with middleware functions.
– server.js
: initializes routes, runs Express app.
Setup Node.js modules
Change current directory to the root folder of our project, then install Express, Multer, Sharp with the following command:
npm install express multer sharp
Create View for uploading multiple images
In views folder, create index.html
with the HTML and Javascript code as below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Node.js upload & resize multiple files</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
<style>
div.preview-images > img {
width: 30%;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-8 mt-3">
<h4>Node.js upload & resize multiple files - bezkoder.com</h4>
<form class="mt-4"
action="/multiple-upload"
method="POST"
enctype="multipart/form-data"
>
<input
type="file"
name="images"
multiple
id="input-images"
class="form-control-file border"
/>
<button type="submit" class="btn btn-primary mt-2">Submit</button>
</form>
</div>
</div>
<hr />
<div class="row">
<div class="col-sm-12">
<div class="preview-images"></div>
</div>
</div>
</div>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(function() {
let imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
let filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
let reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML("<img>"))
.attr("src", event.target.result)
.appendTo(placeToInsertImagePreview);
};
reader.readAsDataURL(input.files[i]);
}
}
};
$("#input-images").on("change", function() {
imagesPreview(this, "div.preview-images");
});
});
</script>
</body>
</html>
The HTML code is easy to understand, the jQuery script shows preview of the chosen images.
We also use Bootstrap to make the UI more comfortable to read.
Create Controller for the view
Under controllers folder, create home.js
file.
const path = require("path");
const home = (req, res) => {
return res.sendFile(path.join(`${__dirname}/../views/index.html`));
};
module.exports = {
getHome: home
};
Create Controller for processing Images
This is the main code of our Node.js project. The Upload Controller uses both multer & sharp module.
We’re gonna export 3 middleware functions:
uploadImages
resizeImages
getResult
const multer = require("multer");
const sharp = require("sharp");
const multerStorage = multer.memoryStorage();
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith("image")) {
cb(null, true);
} else {
cb("Please upload only images.", false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
const uploadFiles = upload.array("images", 10);
const uploadImages = (req, res, next) => {
uploadFiles(req, res, err => {
if (err instanceof multer.MulterError) {
if (err.code === "LIMIT_UNEXPECTED_FILE") {
return res.send("Too many files to upload.");
}
} else if (err) {
return res.send(err);
}
next();
});
};
const resizeImages = async (req, res, next) => {
if (!req.files) return next();
req.body.images = [];
await Promise.all(
req.files.map(async file => {
const filename = file.originalname.replace(/\..+$/, "");
const newFilename = `bezkoder-${filename}-${Date.now()}.jpeg`;
await sharp(file.buffer)
.resize(640, 320)
.toFormat("jpeg")
.jpeg({ quality: 90 })
.toFile(`upload/${newFilename}`);
req.body.images.push(newFilename);
})
);
next();
};
const getResult = async (req, res) => {
if (req.body.images.length <= 0) {
return res.send(`You must select at least 1 image.`);
}
const images = req.body.images
.map(image => "" + image + " ")
.join("");
return res.send(`Images were uploaded:${images}
`);
};
module.exports = {
uploadImages: uploadImages,
resizeImages: resizeImages,
getResult: getResult
};
In the resizeImages
function, we:
– get each image name and create new name for it with jpeg
extension.
– resize to 640x320
– change the image format to jpeg
– set the quality to 90% of the original image
– save the image file to upload folder
Define routes
We define routes in routes/web.js
like this.
There are 2 routes:
– GET: Home page for the upload form.
– POST "/multiple-upload"
to use three uploadController
functions.
const express = require("express");
const router = express.Router();
const homeController = require("../controllers/home");
const uploadController = require("./../controllers/upload");
let routes = app => {
router.get("/", homeController.getHome);
router.post(
"/multiple-upload",
uploadController.uploadImages,
uploadController.resizeImages,
uploadController.getResult
);
return app.use("/", router);
};
module.exports = routes;
Create Express app server
Finally, we only need to create an Express server.
server.js
const express = require("express");
const app = express();
const initRoutes = require("./routes/web");
app.use(express.urlencoded({ extended: true }));
initRoutes(app);
let port = 3000;
app.listen(port, () => {
console.log(`Running at localhost:${port}`);
});
Run the app
Before running this Node.js app, you must create upload folder in the project root folder.
Run following command:
node src/server.js
If everything is ok, the console shows:
Running at localhost:3000
Open browser with url http://localhost:3000/
and you can check the result now.
Conclusion
Today we’ve learned way to upload multiple images using Express and Multer, we also know how to limit the number of images, resize these images and change the extensions using Sharp.
Happy learning! See you again.
Further Reading
- https://www.npmjs.com/package/multer
- https://www.npmjs.com/package/sharp
- https://www.npmjs.com/package/express
Security:
- Node.js & MySQL: User Authentication & Authorization
- Node.js & PostgreSQL: User Authentication & Authorization
- Node.js + MongoDB: User Authentication & Authorization
It helped me a lot as I am new to nodejs
To be honest, your tutorials are really nice, keep it up! I’ll go ahead and bookmark your website to come back in the future. Many thanks!
One of the best Nodejs tutorials I have ever seen!
Best File Upload with Node.js tutorial I have ever seen! Thanks!
Thanks!
Thanks!
One of the best tutorials I have ever seen !
As a Newbie, I am always browsing online for articles that can benefit me. Thank you
One of the best Node.js tutorial I have ever seen !
One of the best tutorials I have ever seen !
Thanks for this lovely tutorial. It is quite helpful. It would be great if you could create a tutorial for uploading, resizing and storing image in my-sql.
I always enjoy your tutorial.
Thanks for guiding me.
Thanks! This Nodejs tutorial helps me so much.
just to tell you I LOVE YOU. thanks
it will be amazing if you know how to rotate images from mobile with this modules
Many thanks! Your tutorial helps me alot.
Excellent tutorial!
I can find this project on your GitHub page. Can you make it available to download?
I enjoy this Node.js tutorial a lot, thanks!
Hey there thanks for the awesome tutorial
I tried out the above code the size of the image is reduced but while I upload an image with transparent background the outcome of the images isn’t transparent the background changes to white.
Is there any way I can achieve the desired outcome.
Thanks in advance…!!
Hi, we cannot make a JPEG image transparent. So you can use
sharp
to resize image to a format that allows transparency, like GIF or PNG.This is what I need, I run the Node App and it works. Thanks!
Good explanation for working with images in Node.js. Thanks.
Perfectly composed post! Thanks.
Hello, I enjoy reading this Node.js tutorial, it’s clear and easy to understand. Thank you!