Search code examples
node.jsexif

NodeJS exif returns undefined


Im trying to get exif info from my images. So I've made some scratch. It works but it does not work while using it in the loop

Hi. Im trying to get exif info from my images. So I've made this

const fs = require('fs');
const mime = require('mime');
const exif = require('exif-reader');
const ExifImage = require('exif').ExifImage;

function getFiles(dir, files = []) {
  const fileList = fs.readdirSync(dir);
  for (const file of fileList) {
    const name = `${dir}/${file}`;
    if (fs.statSync(name).isDirectory()) {
      getFiles(name, files);
    } else {
      files.push(name);
    }
  }
  return files;
}

function getEXIF(filepath){
    try {
        new ExifImage({ image : filepath }, function (error, exifData) {
            if (error)
                console.log('Error: '+error.message);
            else
                console.log(exifData.image); 
        });
    } catch (error) {
        console.log('Error: ' + error.message);
    }
}


//getEXIF('D://MyTestImage.jpg')


const filearr=getFiles('D://Photoes', files = [])
filearr.forEach((element) => {
     const ftype=mime.getType(element)
     if (ftype=='image/jpeg'){
         console.log(getEXIF(element))
     }
 }
 );

When I run the function getEXIF for one specific file it works OK. But when I'm trying to use it in foreach loop it returns undefined. Why?. Im sure that element contains path to file because it works perfect for mime.getType function and returns a value.

Please point my mistake.


Solution

  • Fist, you need to refactor your getEXIF() to return the exif data. Since you are not returning anything, you get undefined.

    Second, the ExifImage accepts a callback, which provides the exifData as the second argument.

    function (error, exifData) {}
    

    The easiest way to get the exifData from the callback, and use that to respond back from getEXIF is use a Promise.

    We shall wrap getEXIF within a promise, and then respond back from the ExifImage callback using reject or resolve.

    async function getEXIF(filepath) {
       return new Promise((resolve, reject) => {
           try {
               new ExifImage({ image : filepath }, function (error, exifData) {
                   if (error)
                       reject(error);
                   else
                       resolve(exifData.image); 
               });
           } catch (error) {
               reject(error);
           }
       });
    }
    

    And you can then use it as:

    const exif = await getEXIF('D://MyTestImage.jpg');
    console.log(exif)