数码相机拍照都有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 °ree,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的格式 经度,纬度,高度如下