Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library

I am making this post to capture all meta data from file using exiftools in nodejs.

what is exif data

Exchangeable image file data format is a standard that specifies formats for images file, sound, and ancillary tags used by digital camer…


This content originally appeared on DEV Community and was authored by Sandeep

I am making this post to capture all meta data from file using exiftools in nodejs.

what is exif data

Exchangeable image file data format is a standard that specifies formats for images file, sound, and ancillary tags used by digital cameras, scanners and other systems handling image and sound files recorded by digital cameras.

backend

these library use and install

  • express
  • mongoose
  • cors
  • node-exiftool
  • dist-exiftool
  • multer

package.json

{
  "name": "metadata-extractor",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "dist-exiftool": "^10.53.0",
    "express": "^4.18.1",
    "mongoose": "^6.4.6",
    "multer": "^1.4.5-lts.1",
    "node-exiftool": "^2.3.0"
  }
}

server.js

const express=require('express');
const cors=require('cors');

const metaDataRoute=require('./routes/metadata.route')
require('./services/connection');
const app=express();
const PORT=process.env.PORT|5000;

app.use(express.json());
app.use(cors());
app.use(express.static(__dirname+"./public"));

app.use('/api',metaDataRoute);

app.listen(PORT,()=>{
    console.log(`server is listening on port ${PORT}`)
})

metadata.controller.js

const exiftoolBin = require('dist-exiftool');
const exiftool =  require('node-exiftool');
const fs = require('fs');
const path = require('path');
const MetaDataModel=require("../models/meta.models");

module.exports.createMetaData=(req,res,next)=>{
    try {
        if(!req.file){
            return res.status(404).send({message:"File Not Found",status:404})
        }
    const PHOTO_PATH = path.join(__dirname, '../public/upload/'+req.file.filename)
    const rs = fs.createReadStream(PHOTO_PATH)
    const ep = new exiftool.ExiftoolProcess(exiftoolBin)
    ep.open()
      .then(() => ep.readMetadata(rs, ['-File:all']))
      .then(async (result) => {
          let metadata=new MetaDataModel({
              fileName:req.file.filename,
              originalName:req.file.originalname,
              size:req.file.size,
              information:result.data[0]
              });
          metadata=await metadata.save();
          return res.send(metadata);
    })
    .then(() => ep.close(), () => ep.close())
    .catch(console.error);

    } catch (error) {
        next(error);
    }
}

module.exports.getAllMetaData=async (req,res,next)=>{
    try {
        let allData=await MetaDataModel.find({}).sort({createdAt:-1});
        res.send(allData)
    } catch (error) {
        next(error)
    }
}

module.exports.deleteMetaData=async (req,res,next)=>{
    try {
        let metadata=await MetaDataModel.findOneAndDelete({_id:req.params.id});
        if(!metadata){
            return res.status(400).send({message:"Metadata not exist"})
        }
        const PHOTO_PATH = path.join(__dirname, '../public/upload/'+metadata.fileName)
        fs.unlink(PHOTO_PATH,(err,data)=>{
            if(err){

            }
        })
        res.send({message:"Deleted Successfully",status:200});
    } catch (error) {
        next(error)
    }
}

middlewares/uploadFile.middleware.js

const multer=require('multer');
const path=require('path');

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname,'../public/upload/'))
  },
  filename: function (req, file, cb) {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
    cb(null, file.fieldname + '-'+uniqueSuffix+'-' +file.originalname)
  }
})

const upload = multer({ storage: storage }).single('file');

module.exports.uploadFile=(req,res,next)=>{
try {
      upload(req, res, function (err) {
    if (err instanceof multer.MulterError) {
        return res.status(400).send({message:"Error: "+err,status:400})
    } else if (err) {
       return res.status(400).send({message:"Error: "+err,status:400})
    }
    next()
  })
} catch (error) {
    next(error);
}
}

middlewres/validateObjectId.middleware.js

const mongoose=require('mongoose');

module.exports.validateObjectId=(req,res,next)=>{
    try {
        if(!mongoose.Types.ObjectId.isValid(req.params.id)){
            return res.status(400).send({message:"Invalid Id"});
        }
        next()
    } catch (error) {
        next(error)
    }
}

metadata.model.js

const mongoose=require('mongoose');

const {Schema,model}=mongoose;

const metaDataSchema=new Schema({
    fileName:{
        type:String,
        required:true,
        index:true
    },
    originalName:{
        type:String
    },
    size:{
        type:Number
    },
    information:{
        type:Object
    }
},{timestamps:true});

const MetaDataModel=model('metadata',metaDataSchema);

module.exports=MetaDataModel;

metadata.route.js

const express=require('express');

const router=express.Router();

const metaDataController=require("../controllers/metadata.controller");
const {uploadFile}=require("../middlewares/uploadFile.middleware");
const {validateObjectId}=require('../middlewares/validateObjectId.middleware')

router.post('/metadata',uploadFile, metaDataController.createMetaData);

router.get('/metadata',metaDataController.getAllMetaData);

router.delete('/metadata/:id',validateObjectId,metaDataController.deleteMetaData);

module.exports=router

services/connection.js

const mongoose=require('mongoose')

module.exports=mongoose.connect('mongodb://localhost:27017/metadata').then((conn)=>{
    console.log('Database Connected');
}).catch((err)=>{
    console.log("Database not connected");
});

Frontend

App.js

import {useState,useEffect} from 'react';
import './App.css';
import Accordian from './Accordian'
import axios from 'axios';

function App() {
  const [file,setFile]= useState();
  const [metaData,setMetadata]=useState([]);
  const BASE_URL='http://localhost:5000/api';
  useEffect(() => {
    getAllData();
  }, [])

  const getAllData=async()=>{
    let data=await axios.get(BASE_URL+'/metadata');
    setMetadata(data?.data);
    console.log(data.data)
  }

  const handleSubmit=async(event)=>{
    event.preventDefault();
    let formData=new FormData();
    formData.append("file",file);
    let uploadMetaData=await axios.post(BASE_URL+'/metadata',formData);
    if(uploadMetaData){
      let metadata=[uploadMetaData.data,...metaData];
      setMetadata(metadata);
      setFile()
    }
  }

  const deleteMetaData=async(id)=>{
    let doc=await axios.delete(BASE_URL+'/metadata/'+id);
    if(doc){
      let metadata=metaData.filter(m=>m._id!==id);
      setMetadata(metadata);
    }
  }
  return (
    <>
    <div className="page-header mt-5">
       <h1>Extract File Upload Control </h1>
    </div>


<div className="container mt-5">
    <div className="">
    </div>
    <div className="col-md-6 mx-auto mt-4">
        <form onSubmit={handleSubmit} method="post" encType="multipart/form-data">
            <input type="file" id="files" onChange={(e)=>setFile(e.target.files[0])} className="form-control" name="files" />
            <p className="mt-4">
                <input type="submit" value="Upload File" disabled={!file} className="btn btn-primary" />
            </p>
        </form>
    </div>
    <div className="col-md-4"></div>
</div>

<div className="col-md-6 mx-auto">
<div className="accordion" id="accordionExample">
      {
        metaData.length>0 && metaData.map((data,index)=>(
      <div key={index}>    
     <Accordian data={data} deleteMetaData={deleteMetaData}></Accordian>
</div>

        ))
      }
     </div> 
</div>
</>
  );
}

export default App;

Accordian.jsx

import React,{useState} from 'react'

const Accordian = ({data,deleteMetaData}) => {
    const [show,setShow]=useState(false);

    const deleteMeta=(id)=>{
      setShow(false);
      deleteMetaData(id);
    }

  return (
    <div className="accordion-item">
    <h2 className="accordion-header" id={'#heading'+data.fileName}>
      <button className="accordion-button" onClick={()=>setShow(!show)} type="button">
        {data?.originalName}
      </button>
    </h2>
    {show &&<div  className="accordion-collapse"  >
      <div className="accordion-body">
        <pre style={{overflowWrap:'break-word'}}>
           {JSON.stringify(data.information,null,2)}
        </pre>
        <div className="text-end">
        <button className="btn btn-danger btn-sm " onClick={()=>deleteMeta(data?._id)}>Delete</button>
        </div>
      </div>
    </div>}
  </div>
  )
}

export default Accordian

App.css

h1{
  text-align: center;
}    
p{
text-align: center; margin-top: 20px; 
}       

response

{
  "SourceFile": "C:/Users/DELL/AppData/Local/Temp/wrote-93199.data",
  "ExifToolVersion": 10.53,
  "Model": "Redmi 5A",
  "ModifyDate": "2019:10:01 16:12:33",
  "YCbCrPositioning": "Centered",
  "ISO": 100,
  "ExposureProgram": "Not Defined",
  "FNumber": 2,
  "ExposureTime": "1/117",
  "SensingMethod": "One-chip color area",
  "SubSecTimeDigitized": "033060",
  "SubSecTimeOriginal": "033060",
  "SubSecTime": "033060",
  "FocalLength": "2.6 mm",
  "Flash": "Off, Did not fire",
  "MeteringMode": "Center-weighted average",
  "SceneCaptureType": "Standard",
  "InteropIndex": "R98 - DCF basic file (sRGB)",
  "InteropVersion": "0100",
  "FocalLengthIn35mmFormat": "3 mm",
  "CreateDate": "2019:10:01 16:12:33",
  "ExifImageHeight": 2592,
  "WhiteBalance": "Auto",
  "DateTimeOriginal": "2019:10:01 16:12:33",
  "BrightnessValue": 3.92,
  "ExifImageWidth": 1944,
  "ExposureMode": "Auto",
  "ApertureValue": 2,
  "ComponentsConfiguration": "Y, Cb, Cr, -",
  "ColorSpace": "sRGB",
  "SceneType": "Directly photographed",
  "ShutterSpeedValue": "1/117",
  "ExifVersion": "0220",
  "FlashpixVersion": "0100",
  "ResolutionUnit": "inches",
  "GPSLatitudeRef": "North",
  "GPSLongitudeRef": "East",
  "GPSAltitudeRef": "Unknown (2)",
  "GPSTimeStamp": "10:42:24",
  "GPSProcessingMethod": "ASCII",
  "GPSDateStamp": "2019:10:01",
  "XResolution": 72,
  "YResolution": 72,
  "Make": "Xiaomi",
  "ThumbnailOffset": 1040,
  "ThumbnailLength": 15180,
  "Compression": "JPEG (old-style)",
  "Aperture": 2,
  "GPSAltitude": "0 m Above Sea Level",
  "GPSDateTime": "2019:10:01 10:42:24Z",
  "GPSLatitude": "25 deg 42' 21.34\" N",
  "GPSLongitude": "81 deg 46' 35.33\" E",
  "GPSPosition": "25 deg 42' 21.34\" N, 81 deg 46' 35.33\" E",
  "ImageSize": "1944x2592",
  "Megapixels": 5,
  "ScaleFactor35efl": 1.1,
  "ShutterSpeed": "1/117",
  "SubSecCreateDate": "2019:10:01 16:12:33.033060",
  "SubSecDateTimeOriginal": "2019:10:01 16:12:33.033060",
  "SubSecModifyDate": "2019:10:01 16:12:33.033060",
  "ThumbnailImage": "(Binary data 15180 bytes, use -b option to extract)",
  "CircleOfConfusion": "0.026 mm",
  "FOV": "161.1 deg",
  "FocalLength35efl": "2.6 mm (35 mm equivalent: 3.0 mm)",
  "HyperfocalDistance": "0.13 m",
  "LightValue": 8.9
}

Image description

this tool to extract media files inner data that not see in file.


This content originally appeared on DEV Community and was authored by Sandeep


Print Share Comment Cite Upload Translate Updates
APA

Sandeep | Sciencx (2022-07-23T10:40:00+00:00) Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library. Retrieved from https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/

MLA
" » Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library." Sandeep | Sciencx - Saturday July 23, 2022, https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/
HARVARD
Sandeep | Sciencx Saturday July 23, 2022 » Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library., viewed ,<https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/>
VANCOUVER
Sandeep | Sciencx - » Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/
CHICAGO
" » Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library." Sandeep | Sciencx - Accessed . https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/
IEEE
" » Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library." Sandeep | Sciencx [Online]. Available: https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/. [Accessed: ]
rf:citation
» Extract All Exif Data from media files in ReactJS and Nodejs Using Exiftool library | Sandeep | Sciencx | https://www.scien.cx/2022/07/23/extract-all-exif-data-from-media-files-in-reactjs-and-nodejs-using-exiftool-library/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.