mirror of
https://github.com/subsurface/subsurface.git
synced 2024-12-11 03:21:29 +00:00
Compute dive computer/camera time offset from sample picture
Signed-off-by: Robert C. Helling <helling@atdotde.de> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
fe2a264db3
commit
bbb071f1e8
5 changed files with 216 additions and 35 deletions
|
@ -804,6 +804,7 @@ void DiveListView::loadImages()
|
||||||
{
|
{
|
||||||
struct memblock mem;
|
struct memblock mem;
|
||||||
EXIFInfo exif;
|
EXIFInfo exif;
|
||||||
|
int retval;
|
||||||
time_t imagetime;
|
time_t imagetime;
|
||||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Image Files"), lastUsedImageDir(), tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
|
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Image Files"), lastUsedImageDir(), tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
|
||||||
|
|
||||||
|
@ -818,23 +819,16 @@ void DiveListView::loadImages()
|
||||||
updateLastImageTimeOffset(shiftDialog.amount());
|
updateLastImageTimeOffset(shiftDialog.amount());
|
||||||
|
|
||||||
for (int i = 0; i < fileNames.size(); ++i) {
|
for (int i = 0; i < fileNames.size(); ++i) {
|
||||||
struct tm tm;
|
|
||||||
int year, month, day, hour, min, sec;
|
|
||||||
int retval;
|
|
||||||
if (readfile(fileNames.at(i).toUtf8().data(), &mem) <= 0)
|
if (readfile(fileNames.at(i).toUtf8().data(), &mem) <= 0)
|
||||||
continue;
|
continue;
|
||||||
retval = exif.parseFrom((const unsigned char *) mem.buffer, (unsigned) mem.size);
|
retval = exif.parseFrom((const unsigned char *) mem.buffer, (unsigned) mem.size);
|
||||||
free(mem.buffer);
|
free(mem.buffer);
|
||||||
if (retval != PARSE_EXIF_SUCCESS)
|
if (retval != PARSE_EXIF_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
sscanf(exif.DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
|
imagetime = shiftDialog.epochFromExiv(&exif);
|
||||||
tm.tm_year = year;
|
if (!imagetime)
|
||||||
tm.tm_mon = month - 1;
|
continue;
|
||||||
tm.tm_mday = day;
|
imagetime += shiftDialog.amount();
|
||||||
tm.tm_hour = hour;
|
|
||||||
tm.tm_min = min;
|
|
||||||
tm.tm_sec = sec;
|
|
||||||
imagetime = utc_mktime(&tm) + shiftDialog.amount();
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
for_each_dive(j, dive){
|
for_each_dive(j, dive){
|
||||||
|
|
|
@ -52,6 +52,7 @@ public slots:
|
||||||
void shiftTimes();
|
void shiftTimes();
|
||||||
void loadImages();
|
void loadImages();
|
||||||
void uploadToDivelogsDE();
|
void uploadToDivelogsDE();
|
||||||
|
QString lastUsedImageDir();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentDiveChanged(int divenr);
|
void currentDiveChanged(int divenr);
|
||||||
|
@ -73,7 +74,6 @@ private:
|
||||||
void restoreExpandedRows();
|
void restoreExpandedRows();
|
||||||
int lastVisibleColumn();
|
int lastVisibleColumn();
|
||||||
void selectTrip ( dive_trip_t* trip );
|
void selectTrip ( dive_trip_t* trip );
|
||||||
QString lastUsedImageDir();
|
|
||||||
void updateLastUsedImageDir(const QString& s);
|
void updateLastUsedImageDir(const QString& s);
|
||||||
void updateLastImageTimeOffset(int offset);
|
void updateLastImageTimeOffset(int offset);
|
||||||
int lastImageTimeOffset();
|
int lastImageTimeOffset();
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>343</width>
|
<width>693</width>
|
||||||
<height>177</height>
|
<height>606</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item alignment="Qt::AlignTop">
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Shift times of image(s) by</string>
|
<string>Shift times of image(s) by</string>
|
||||||
|
@ -40,6 +40,16 @@
|
||||||
<day>1</day>
|
<day>1</day>
|
||||||
</date>
|
</date>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="maximumDateTime">
|
||||||
|
<datetime>
|
||||||
|
<hour>23</hour>
|
||||||
|
<minute>59</minute>
|
||||||
|
<second>59</second>
|
||||||
|
<year>2010</year>
|
||||||
|
<month>12</month>
|
||||||
|
<day>31</day>
|
||||||
|
</datetime>
|
||||||
|
</property>
|
||||||
<property name="minimumDateTime">
|
<property name="minimumDateTime">
|
||||||
<datetime>
|
<datetime>
|
||||||
<hour>0</hour>
|
<hour>0</hour>
|
||||||
|
@ -51,14 +61,32 @@
|
||||||
</datetime>
|
</datetime>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumDate">
|
<property name="maximumDate">
|
||||||
|
<date>
|
||||||
|
<year>2010</year>
|
||||||
|
<month>12</month>
|
||||||
|
<day>31</day>
|
||||||
|
</date>
|
||||||
|
</property>
|
||||||
|
<property name="minimumDate">
|
||||||
<date>
|
<date>
|
||||||
<year>2000</year>
|
<year>2000</year>
|
||||||
<month>1</month>
|
<month>1</month>
|
||||||
<day>1</day>
|
<day>1</day>
|
||||||
</date>
|
</date>
|
||||||
</property>
|
</property>
|
||||||
<property name="displayFormat">
|
<property name="maximumTime">
|
||||||
<string>h:mm</string>
|
<time>
|
||||||
|
<hour>23</hour>
|
||||||
|
<minute>59</minute>
|
||||||
|
<second>59</second>
|
||||||
|
</time>
|
||||||
|
</property>
|
||||||
|
<property name="minimumTime">
|
||||||
|
<time>
|
||||||
|
<hour>0</hour>
|
||||||
|
<minute>0</minute>
|
||||||
|
<second>0</second>
|
||||||
|
</time>
|
||||||
</property>
|
</property>
|
||||||
<property name="timeSpec">
|
<property name="timeSpec">
|
||||||
<enum>Qt::LocalTime</enum>
|
<enum>Qt::LocalTime</enum>
|
||||||
|
@ -82,19 +110,113 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>To compute the offset between the clocks of your dive computer and your camera use your camera to take a picture of your dive compuer displaying the current time. Download that image to your computer and press this button.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="syncCamera">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Determine camera time offset</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Select image of divecomputer showing time</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="displayDC">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<widget class="QDateTimeEdit" name="dcTime">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>70</y>
|
||||||
|
<width>161</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>234</width>
|
||||||
|
<height>60</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Which date and time are displayed on the image?</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QGraphicsView" name="DCImage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>260</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>361</width>
|
||||||
|
<height>281</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -12,8 +12,11 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include "exif.h"
|
||||||
#include "../dive.h"
|
#include "../dive.h"
|
||||||
|
#include "../file.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
class MinMaxAvgWidgetPrivate {
|
class MinMaxAvgWidgetPrivate {
|
||||||
|
@ -168,23 +171,80 @@ void ShiftImageTimesDialog::buttonClicked(QAbstractButton* button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShiftImageTimesDialog::syncCameraClicked()
|
||||||
|
{
|
||||||
|
struct memblock mem;
|
||||||
|
EXIFInfo exiv;
|
||||||
|
int retval;
|
||||||
|
QPixmap picture;
|
||||||
|
QDateTime dcDateTime = QDateTime::QDateTime();
|
||||||
|
QStringList fileNames = QFileDialog::getOpenFileNames(this,
|
||||||
|
tr("Open Image File"),
|
||||||
|
MainWindow().dive_list()->lastUsedImageDir(),
|
||||||
|
tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
|
||||||
|
|
||||||
|
if (fileNames.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
picture.load(fileNames.at(0));
|
||||||
|
ui.displayDC->setEnabled(TRUE);
|
||||||
|
QGraphicsScene *scene = new QGraphicsScene (this);
|
||||||
|
|
||||||
|
scene->addPixmap(picture.scaled(ui.DCImage->size()));
|
||||||
|
ui.DCImage->setScene(scene);
|
||||||
|
if (readfile(fileNames.at(0).toUtf8().data(), &mem) <= 0)
|
||||||
|
return;
|
||||||
|
retval = exiv.parseFrom((const unsigned char *) mem.buffer, (unsigned) mem.size);
|
||||||
|
free(mem.buffer);
|
||||||
|
if (retval != PARSE_EXIF_SUCCESS)
|
||||||
|
return;
|
||||||
|
dcImageEpoch = epochFromExiv(&exiv);
|
||||||
|
dcDateTime.setTime_t(dcImageEpoch);
|
||||||
|
ui.dcTime->setDateTime(dcDateTime);
|
||||||
|
connect(ui.dcTime, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(dcDateTimeChanged(const QDateTime &)));
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t ShiftImageTimesDialog::epochFromExiv(EXIFInfo *exif)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
int year, month, day, hour, min, sec;
|
||||||
|
|
||||||
|
sscanf(exif->DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
|
||||||
|
tm.tm_year = year;
|
||||||
|
tm.tm_mon = month - 1;
|
||||||
|
tm.tm_mday = day;
|
||||||
|
tm.tm_hour = hour;
|
||||||
|
tm.tm_min = min;
|
||||||
|
tm.tm_sec = sec;
|
||||||
|
return (utc_mktime(&tm));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShiftImageTimesDialog::dcDateTimeChanged(const QDateTime &newDateTime)
|
||||||
|
{
|
||||||
|
if (!dcImageEpoch)
|
||||||
|
return;
|
||||||
|
setOffset(newDateTime.toTime_t() - dcImageEpoch);
|
||||||
|
}
|
||||||
|
|
||||||
ShiftImageTimesDialog::ShiftImageTimesDialog(QWidget *parent): QDialog(parent), m_amount(0)
|
ShiftImageTimesDialog::ShiftImageTimesDialog(QWidget *parent): QDialog(parent), m_amount(0)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
|
connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
|
||||||
|
connect(ui.syncCamera, SIGNAL(clicked()), this, SLOT(syncCameraClicked()));
|
||||||
|
dcImageEpoch = (time_t) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ShiftImageTimesDialog::amount() const
|
time_t ShiftImageTimesDialog::amount() const
|
||||||
{
|
{
|
||||||
return m_amount;
|
return m_amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShiftImageTimesDialog::setOffset(int offset)
|
void ShiftImageTimesDialog::setOffset(time_t offset)
|
||||||
{
|
{
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
ui.forward->setDown(TRUE);
|
ui.forward->setChecked(TRUE);
|
||||||
} else {
|
} else {
|
||||||
ui.backwards->setDown(TRUE);
|
ui.backwards->setChecked(TRUE);
|
||||||
offset *= -1;
|
offset *= -1;
|
||||||
}
|
}
|
||||||
ui.timeEdit->setTime(QTime::QTime(offset / 3600, (offset % 3600) / 60, offset % 60));
|
ui.timeEdit->setTime(QTime::QTime(offset / 3600, (offset % 3600) / 60, offset % 60));
|
||||||
|
|
|
@ -10,6 +10,7 @@ class QAbstractButton;
|
||||||
#include "ui_renumber.h"
|
#include "ui_renumber.h"
|
||||||
#include "ui_shifttimes.h"
|
#include "ui_shifttimes.h"
|
||||||
#include "ui_shiftimagetimes.h"
|
#include "ui_shiftimagetimes.h"
|
||||||
|
#include "exif.h"
|
||||||
|
|
||||||
class MinMaxAvgWidget : public QWidget{
|
class MinMaxAvgWidget : public QWidget{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -59,13 +60,17 @@ class ShiftImageTimesDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ShiftImageTimesDialog(QWidget *parent);
|
explicit ShiftImageTimesDialog(QWidget *parent);
|
||||||
int amount() const;
|
time_t amount() const;
|
||||||
void setOffset(int offset);
|
void setOffset(time_t offset);
|
||||||
|
time_t epochFromExiv(EXIFInfo *exif);
|
||||||
private slots:
|
private slots:
|
||||||
void buttonClicked(QAbstractButton *button);
|
void buttonClicked(QAbstractButton *button);
|
||||||
|
void syncCameraClicked();
|
||||||
|
void dcDateTimeChanged(const QDateTime &);
|
||||||
private:
|
private:
|
||||||
Ui::ShiftImageTimesDialog ui;
|
Ui::ShiftImageTimesDialog ui;
|
||||||
int m_amount;
|
time_t m_amount;
|
||||||
|
time_t dcImageEpoch;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isGnome3Session();
|
bool isGnome3Session();
|
||||||
|
|
Loading…
Reference in a new issue