I want to display multiple images on my website, using Multer (nodejs).
I have created the following function:
exports.upload = multer(options).array('photo',3);
exports.images = async (req, res, next) => {
const imgArray = req.files;
const imgFormat = [];
for(let i = 0; i < imgArray.length; i++ ) {
imgFormat.push(imgArray[i].mimetype.split('/')[1] );
}
req.body.photo = [];
for(let i = 0; i < imgArray.length; i++ ) {
req.body.photo.push(`${uuid.v4()}.${imgFormat[i]}`);
}
for (let i = 0; i < imgArray.length; i++) {
const imgDetails = imgArray[i];
const photo = await jimp.read(imgDetails.buffer);
await photo.resize(1200, jimp.AUTO);
await photo.write(`./public/uploads/${(req.body.photo)}`)
}
next();
console.log(req.body.photo);
};
I use mongoose to access my database. On MongoDB, I manage to retrieve the images without facing any issue:
see what I get in MongoDB
But when I console.log req.body.photo, I get the following array:
[ 'cdb88df7-149d-4506-9ec2-7550c32ace66.jpeg',
'efd9113b-9bd1-410e-a402-e969bf7aa8e3.png',
'6408dbdc-4093-44a9-91f1-e34e7c5918e1.jpeg' ]
In my memoryStorage, I save a string made of three images when I need them to be separated:
What i get: cdb88df7-149d-4506-9ec2-7550c32ace66.jpeg,efd9113b-9bd1-410e-a402-e969bf7aa8e3.png,6408dbdc-4093-44a9-91f1-e34e7c5918e1.jpeg
What I want:
cdb88df7-149d-4506-9ec2-7550c32ace66.jpeg
efd9113b-9bd1-410e-a402-e969bf7aa8e3.png
6408dbdc-4093-44a9-91f1-e34e7c5918e1.jpeg
Getting the images separated from each other and not in an array make my code work, I have tested it.
Would you please tell me how to do so? I ran out of ideas. Many thanks
You could try and assign variables to your images using the new ES6's Array Destructuring
As from Docs:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
hence like so
let [imageOne, imageTwo, imageThree] = req.body.photo;
Then you can use the images separately the way you want if you console.log() imageOne you will get
console.log(imageOne) //output cdb88df7-149d-4506-9ec2-7550c32ace66.jpeg
In you code you could implement it like this
exports.upload = multer(options).array('photo',3);
exports.images = async (req, res, next) => {
const imgArray = req.files;
const imgFormat = [];
for(let i = 0; i < imgArray.length; i++ ) {
imgFormat.push(imgArray[i].mimetype.split('/')[1] );
}
req.body.photo = [];
for(let i = 0; i < imgArray.length; i++ ) {
req.body.photo.push(`${uuid.v4()}.${imgFormat[i]}`);
}
for (let i = 0; i < imgArray.length; i++) {
const imgDetails = imgArray[i];
const photo = await jimp.read(imgDetails.buffer);
await photo.resize(1200, jimp.AUTO);
await photo.write(`./public/uploads/${(req.body.photo)}`)
}
setTimeout(() => {
let [imageOne, imageTwo, imageThree] = req.body.photo;
}, 450);
setTimeout(() => {
next();
}, 600);
};
What if you tried and do this instead of the forloop to later identify what the actual problem is cause I think it might be the loop
let [firstFile,secondFile,thirdFile] = req.files
const photo1 = await jimp.read(firstFile.buffer);
const photo2 = await jimp.read(secondFile.buffer);
const photo3 = await jimp.read(thirdFile.buffer);
await photo1.resize(600, jimp.AUTO);
await photo2.resize(600, jimp.AUTO);
await photo3.resize(600, jimp.AUTO);
await photo1.write(`./public/uploads/${(firstFile)}`);
await photo2.write(`./public/uploads/${(secondFile)}`);
await photo3.write(`./public/uploads/${(thirdFile)}`);
Thanks @chuklore for your answer, Besides allowing me to learn a new ES6's practice, you helped me move forward with my problem. But I am still facing an issue after I have implemented your recommandation.
Now, I am able to get images separated from each other: i.ibb.co/n8TbdhM/image.png
So when I loop with PUG, I get three images as wanted BUT it always the same image: i.ibb.co/BTDPWN5/image.png
As you can see in the above screenshot, I am looping via PUG through what should have been three different images.
When I check those images in my memory storage, it's indeed the same image with different UUID.
So something must have gone wrong in my code but I cannot figure it out. When in console.log(imgDetails.buffer), I get three different buffer, not always the same. So I don't know where the issue is coming from:
console.log(imgDetails.buffer): https://i.ibb.co/XVFzz4x/image.png
Here is my code again:
exports.images = async (req, res, next) => {
// get all images details
const imgArray = req.files;
// get extension (pgn, jpeg...)
const imgFormat = [];
for(let i = 0; i < imgArray.length; i++ ) {
imgFormat.push(imgArray[i].mimetype.split('/')[1] );
}
// get unique ID by image
req.body.photo = [];
for(let i = 0; i < imgArray.length; i++ ) {
req.body.photo.push(`${uuid.v4()}.${imgFormat[i]}`);
}
// unpack images from the array
let [imageOne, imageTwo, imageThree] = req.body.photo;
for (let i = 0; i < imgArray.length; i++) {
const imgDetails = imgArray[i];
// get buffer for each image
const photo = await jimp.read(imgDetails.buffer);
await photo.resize(600, jimp.AUTO);
await photo.write(`./public/uploads/${(imageOne)}`);
await photo.write(`./public/uploads/${(imageTwo)}`);
await photo.write(`./public/uploads/${(imageThree)}`)
}
next();
};
I can provide details about the rest of my code if needed. Thanks
@chuklore. Thanks a lot for your help, I managed to get it worked by following your valuable instructions and add up small modifications. Here the code that works fine on my side:
exports.image = async (req, res, next) => {
if(!req.files){
next();
return;
}
let [firstFile,secondFile, thirdFile] = req.files;
const extension1 = firstFile.mimetype.split('/')[1];
const extension2 = secondFile.mimetype.split('/')[1];
const extension3 = thirdFile.mimetype.split('/')[1];
req.body.photo = [
`${uuid.v4()}.${extension1}`,
`${uuid.v4()}.${extension2}`,
`${uuid.v4()}.${extension3}`];
let [imageOne, imageTwo, imageThree] = req.body.photo;
const photo1 = await jimp.read(firstFile.buffer);
const photo2 = await jimp.read(secondFile.buffer);
const photo3 = await jimp.read(thirdFile.buffer);
await photo1.resize(600, jimp.AUTO);
await photo2.resize(600, jimp.AUTO);
await photo3.resize(600, jimp.AUTO);
await photo1.write(`./public/uploads/${(imageOne)}`);
await photo2.write(`./public/uploads/${(imageTwo)}`);
await photo3.write(`./public/uploads/${(imageThree)}`);
next();
};
If anyone think of any way to improve it, please let me know. Because assuming that I want 50 images on my website, I cannot duplicate 50 times each line.
Also, when I upload just one image (instead of three), I end up with a "Cannot read property 'mimetype' of undefined". Obviously, uploading three images is mandatory, but I don't want it to be so.
I have tried many things like:
for(let i=0; i < req.files.length; i++ ) {
if( typeof req.files[i].mimetype ==='undefined') {
// ...
}
Nothing works so far. Any idea? Thanks
For those who are interested, here is my final code that resolved all issues mentionned above:
exports.images = async (req, res, next) => {
const imgArray = req.files;
const imgFormat = [];
for(let i = 0; i < imgArray.length; i++ ) {
imgFormat.push(imgArray[i].mimetype.split('/')[1] );
}
req.body.photo = [];
for(let i = 0; i < imgArray.length; i++ ) {
req.body.photo.push(`${uuid.v4()}.${imgFormat[i]}`);
}
for (let i = 0; i < imgArray.length; i++) {
const imgDetails = imgArray[i];
const photo = await jimp.read(imgDetails.buffer);
await photo.resize(1200, jimp.AUTO);
await photo.write(`./public/uploads/${(req.body.photo[i])}`)
}
next();
};
With this code, i am able to upload multiple images via multer and jimp. Many thanks to @ for your help
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.