Exiv2 照片GPS信息添加

发布时间 2023-06-27 15:56:07作者: 一杯清酒邀明月

数码相机拍照都有EXIF信息,GPS信息就是加在EXIF里的;
Exiv2是一个开源的项目用来读写照片的EXIF信息,附上官网https://www.exiv2.org/
关于Exiv2和EXIF的介绍网上的资料很多,不在多介绍
结合官方的例子(https://www.exiv2.org/doc/examples.html),用Qt对Exiv2进行简单的封装实现添加GPS添加和EXIF信息查询
.h文件

 1 #include <QObject>
 2 #include<QString>
 3 #include"exiv2/exiv2.hpp"
 4 using namespace std;
 5 
 6 //经度  纬度  高度
 7 const QString GPS_Longitude="Exif.GPSInfo.GPSLongitude";
 8 const QString GPS_Latitude="Exif.GPSInfo.GPSLatitude";
 9 const QString GPS_Altitude="Exif.GPSInfo.GPSAltitude";
10 
11 class ImageAnalysis : public QObject
12 {
13     Q_OBJECT
14 public:
15     explicit ImageAnalysis(QObject *parent = nullptr);
16 public:
17     //重新设置分析的照片
18     void Reset(const QString &imagePath);
19     //添加GPS信息
20     bool AddExifGPSInfo(const QString &keyStr, const QString &value);
21     //设置完后,把数据写入
22     bool WriteExifData();
23     //查找一个ExifKey避免没有的Key产生段错误  目前没有用
24     QString FindExifKey(const QString &key);
25 private:
26     //照片的路径
27     QString m_imagePath;
28     std::auto_ptr<Exiv2::Image> m_imagePtr;
29     Exiv2::ExifData m_ed;
30 private:
31     //度转度分秒
32     QStringList DegreeToDDMMSS(const QString& degree);
33     QString GetDDMMSS(const QString& degree,int n,bool bEnd=false);
34     QString DDMMSSToExivGps(QStringList &strList);//把度分秒转换为exiv 保存的gps字符串格式
35     QString AltitudeToExiivGps(const QString &altitude);//把高度转换为exiv 保存的gps字符串格式
36 };

.cpp文件

  1 #include "imageanalysis.h"
  2 #include<QDebug>
  3 #include<iostream>
  4 #include<QMessageBox>
  5 #include<qmath.h>
  6 using namespace std;
  7 
  8 ImageAnalysis::ImageAnalysis(QObject *parent) : QObject(parent),m_imagePath("")
  9 {
 10 }
 11 
 12 void ImageAnalysis::Reset(const QString &imagePath)
 13 {
 14     m_imagePath=imagePath;
 15     std::string temp=m_imagePath.toLocal8Bit();
 16     //std::cout<<"temp:  "<<temp<<std::endl;
 17     m_imagePtr=Exiv2::ImageFactory::open(temp);
 18     if (m_imagePtr.get() == 0)
 19     {
 20         qDebug()<< "Read Exif Error.";
 21         QMessageBox::information(NULL,tr(""),tr("img读取错误"),QMessageBox::Ok);
 22         return;
 23     }
 24     m_imagePtr->readMetadata();
 25     m_ed.clear();
 26     m_ed=m_imagePtr->exifData();
 27 }
 28 //读取exif信息
 29 QString ImageAnalysis::FindExifKey(const QString &key)
 30 {
 31     std::string _key=key.toLocal8Bit();
 32     Exiv2::ExifKey tmp = Exiv2::ExifKey(_key);
 33     Exiv2::ExifData::iterator pos = m_ed.findKey(tmp);
 34     if (pos == m_ed.end()) {
 35         return "Unknow";
 36     }
 37     return QString::fromLocal8Bit(pos->value().toString().data());
 38 }
 39 /// \brief ImageAnalysis::AddExifGPSInfo 添加EXIF GPS信息
 40 /// \param keyStr exif key值 Exif.GPSInfo.GPSLongitude 经度  Exif.GPSInfo.GPSLatitude  纬度 Exif.GPSInfo.GPSAltitude  高度
 41 /// \param value  exif value
 42 /// \return
 43 bool ImageAnalysis::AddExifGPSInfo(const QString &keyStr,const QString& value)
 44 {
 45     QStringList tempList;
 46     QString tempValue;
 47     if(keyStr=="Exif.GPSInfo.GPSAltitude")
 48     {
 49         tempValue=AltitudeToExiivGps(value);
 50     }
 51     else
 52     {
 53         tempList= DegreeToDDMMSS(value);
 54         tempValue= DDMMSSToExivGps(tempList);
 55     }
 56     std::string _keyStr=keyStr.toLocal8Bit();
 57     std::string _value=tempValue.toLocal8Bit();
 58     Exiv2::ExifKey tmp=Exiv2::ExifKey(_keyStr);
 59     Exiv2::ExifData::iterator pos=m_ed.findKey(tmp);
 60     //重复判断
 61     if (pos == m_ed.end())
 62     {
 63         Exiv2::URationalValue::AutoPtr rv(new Exiv2::URationalValue);
 64         //从一个字符串中设置rational组件
 65         rv->read(_value);
 66         Exiv2::ExifKey key = Exiv2::ExifKey(_keyStr);
 67         m_ed.add(key, rv.get());
 68     }
 69     else//exif有 key
 70     {
 71         //获取指向该值副本的指针 Exiv2::Value::AutoPtr
 72         Exiv2::Value::AutoPtr v = pos->getValue();
 73         //将值指针向下强制转换为其实际类型
 74         Exiv2::URationalValue* prv = dynamic_cast<Exiv2::URationalValue*>(v.release());
 75         if (prv == 0)
 76             throw Exiv2::Error(Exiv2::kerErrorMessage, "Downcast failed");
 77         Exiv2::URationalValue::AutoPtr rv(prv);
 78         rv->read(_value);
 79         pos->setValue(rv.get());
 80     }
 81     WriteExifData();
 82     return true;
 83 }
 84 
 85 ///把修改的数据写入
 86 bool ImageAnalysis::WriteExifData()
 87 {
 88     if(m_imagePtr.get()!=0)
 89     {
 90         m_imagePtr->setExifData(m_ed);
 91         m_imagePtr->writeMetadata();
 92         //qDebug()<<QString::fromLocal8Bit("修改成功");
 93         return true;
 94     }
 95     return false;
 96 }
 97 ///度转度分秒,秒保留小数点后4位
 98 QStringList ImageAnalysis::DegreeToDDMMSS(const QString& degree)
 99 {
100     QStringList qlist;
101     QString dd,mm,ss;
102     if(!degree.contains("."))
103     {
104          dd=degree;
105     }
106     else
107     {
108         dd=GetDDMMSS(degree,1);
109         mm=GetDDMMSS(degree,2);
110         ss=GetDDMMSS(degree,3,true);
111     }
112     qlist<<dd<<mm<<ss;
113     return qlist;
114 }
115 
116 // 根据n的值递归求度,分,秒
117 QString ImageAnalysis::GetDDMMSS(const QString &degree,int n,bool bEnd)
118 {
119     QStringList list=degree.split(".");
120     if(n==1)
121     {
122         if(bEnd==false)
123             return list.at(0);
124         else
125             return degree;
126     }
127     while (n--)
128     {
129         QString temp=list.at(1);
130         int len=temp.length();
131         double d=60.0*temp.toDouble()/(double)qPow(10,len);
132         return GetDDMMSS(QString::number(d,'g',12),n,bEnd);
133     }
134 }
135 ///经纬度转换为EXIF信息 如:113.211  133/1 12/1 396000/10000 
136 QString ImageAnalysis::DDMMSSToExivGps(QStringList &strList)
137 {
138     if(strList.length()!=3)
139     {
140         QMessageBox::information(NULL,tr("提示"),tr("longitude and latitude error"),QMessageBox::Ok);
141         return "0";
142     }
143     QString dd,mm,ss;
144     dd=strList.at(0)+"/1 ";
145     mm=strList.at(1)+"/1 ";
146     ss=strList.at(2);
147     ss=AltitudeToExiivGps(ss);
148     return dd+mm+ss;
149 }
150 //数字字符串转化为exif,保留到小数点后四位,39.6转换后396000/10000
151 QString ImageAnalysis::AltitudeToExiivGps(const QString &altitude)
152 {
153     QString temp=altitude;
154     if(!altitude.contains("."))
155     {
156         return altitude+"/1";
157     }
158     QString fz,after,front;
159     QStringList tList=altitude.split(".");
160     //小数点前
161     front=tList.at(0);
162     //小数点后,截取前四位
163     after=tList.at(1)+"0000";
164     after=after.mid(0,4);
165     //整理后的分子
166     fz=front+after;
167     return fz+"/10000";
168 }

后面就是一些目录和文件的操作;
具体的程序如下:

 主要功能是读取文件夹目录下的所有照片,读取一个txt文件的内容,其中
txt的格式 经度,纬度,高度如下