简体   繁体   中英

Issues when trying to upload multiple images from Multer using Jimp (Express) in NodeJS

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM