-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexiftool.cpp
More file actions
82 lines (74 loc) · 3.09 KB
/
exiftool.cpp
File metadata and controls
82 lines (74 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "exiftool.h"
#include "util.h"
#include <QProcess>
#include <QRegularExpression>
bool ExifTool::available(QString *verOut, QString *errOut){
QProcess p;
p.start("exiftool", {"-ver"});
if(!p.waitForStarted(4000)){ if(errOut) *errOut="cannot start exiftool"; return false; }
if(!p.waitForFinished(6000)){ if(errOut) *errOut="exiftool timeout"; return false; }
if(p.exitCode()!=0){ if(errOut) *errOut="exiftool non-zero exit"; return false; }
if(verOut) *verOut = QString::fromUtf8(p.readAllStandardOutput()).trimmed();
return true;
}
QString ExifTool::run(const QString& f, const QStringList& args, QString* errOut){
QProcess p;
QStringList a=args; a<<f;
p.start("exiftool", a);
p.waitForFinished(-1);
if(errOut) *errOut = QString::fromUtf8(p.readAllStandardError());
return QString::fromUtf8(p.readAllStandardOutput());
}
QString ExifTool::dumpAll(const QString& f, QString* errOut){
return run(f, {}, errOut);
}
QString ExifTool::dumpGpsRaw(const QString& f){
return run(f, {"-c","%.6f","-GPSPosition"});
}
bool ExifTool::stripAll(const QString& f, bool keepBackup, QString* ioMsg){
QStringList args; args<<"-all=";
if(!keepBackup) args<<"-overwrite_original";
QString msg; run(f, args, &msg);
if(ioMsg) *ioMsg=msg;
return QFileInfo::exists(f);
}
GpsResult ExifTool::analyze(const QString& f){
GpsResult r; r.path=f; r.bytes=QFileInfo(f).size(); r.sha256=sha256File(f);
QString err;
const QString all = dumpAll(f, &err);
const QString gps = dumpGpsRaw(f);
auto parseLatLon=[&](const QString &s, double &la, double &lo, bool &ok){
ok=false;
QRegularExpression reNum(R"(([+-]?\d+(?:\.\d+)?))");
auto it=reNum.globalMatch(s);
QList<double> nums; while(it.hasNext()) nums << it.next().captured(1).toDouble();
if(nums.size()>=2){ la=nums[0]; lo=nums[1]; ok=true; return; }
QRegularExpression laRe(R"(GPS Latitude\s*:\s*([+-]?\d+(?:\.\d+)?))", QRegularExpression::CaseInsensitiveOption);
QRegularExpression loRe(R"(GPS Longitude\s*:\s*([+-]?\d+(?:\.\d+)?))", QRegularExpression::CaseInsensitiveOption);
auto m1 = laRe.match(all);
auto m2 = loRe.match(all);
if(m1.hasMatch() && m2.hasMatch()){ la=m1.captured(1).toDouble(); lo=m2.captured(1).toDouble(); ok=true; }
};
double la=0, lo=0; bool ok=false;
if(!gps.trimmed().isEmpty()){
r.gpsLine = gps.trimmed();
parseLatLon(r.gpsLine, la, lo, ok);
}
if(!ok){
QTextStream ts(const_cast<QString*>(&const_cast<QString&>(all)), QIODevice::ReadOnly);
while(!ts.atEnd()){
const QString L=ts.readLine();
if(L.contains("GPS", Qt::CaseInsensitive)) r.gpsLines<<L;
}
if(!r.gpsLines.isEmpty()){
r.gpsLine = r.gpsLines.join("\n");
parseLatLon(r.gpsLine, la, lo, ok);
}
}
r.hasGps=ok; r.lat=la; r.lon=lo;
if(ok){
r.osmUrl = QString("https://www.openstreetmap.org/?mlat=%1&mlon=%2&zoom=12")
.arg(QString::number(la,'f',6)).arg(QString::number(lo,'f',6));
}
return r;
}