From 33a6cce45a86b74f2e596253876f8bad71844ea4 Mon Sep 17 00:00:00 2001 From: "Robert C. Helling" Date: Mon, 23 Feb 2015 12:00:55 +0100 Subject: [PATCH 2/4] Save and use database of image hashes. This patch adds a directory crawler to compute hashes of image files and load and save those to a persistent file. Signed-off-by: Robert C. Helling --- qt-ui/divepicturewidget.cpp | 16 +++++++---- qt-ui/mainwindow.cpp | 4 +++ qthelper.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++ qthelper.h | 6 ++++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/qt-ui/divepicturewidget.cpp b/qt-ui/divepicturewidget.cpp index 4a205da..d4b29e6 100644 --- a/qt-ui/divepicturewidget.cpp +++ b/qt-ui/divepicturewidget.cpp @@ -3,22 +3,26 @@ #include "dive.h" #include "divelist.h" #include +#include #include #include #include +#include SHashedImage::SHashedImage(struct picture *picture) : QImage(picture->filename) { if (isNull()) { // Hash lookup. + qDebug() << picture->filename << "not found, trying" << picture->hash << MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)]; + load(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)]); + if (!isNull()) + QtConcurrent::run(updateHash, picture); } else { - QCryptographicHash hash(QCryptographicHash::Sha1); - QFile imagefile(picture->filename); - imagefile.open(QIODevice::ReadOnly); - hash.addData(&imagefile); + QByteArray hash = hashFile(picture->filename); free(picture->hash); - picture->hash = strdup(hash.result().toHex().data()); - MainWindow::instance()->hashOf.insert(QString(picture->filename), hash.result()); + picture->hash = strdup(hash.toHex().data()); + MainWindow::instance()->hashOf.insert(QString(picture->filename), hash); + MainWindow::instance()->localFilenameOf[hash] = QString(picture->filename); } } diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index 648ead1..a0fbaeb 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -37,6 +37,7 @@ #endif #include #include +#include MainWindow *MainWindow::m_Instance = NULL; @@ -50,6 +51,8 @@ MainWindow::MainWindow() : QMainWindow(), Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!"); m_Instance = this; ui.setupUi(this); + read_hashes(); + learnImages(QDir("/Users/helling/Pictures/subsurfaceimages.away"), 3); // Define the States of the Application Here, Currently the states are situations where the different // widgets will change on the mainwindow. @@ -201,6 +204,7 @@ MainWindow::MainWindow() : QMainWindow(), MainWindow::~MainWindow() { + write_hashes(); m_Instance = NULL; } diff --git a/qthelper.cpp b/qthelper.cpp index d449268..a58a21d 100644 --- a/qthelper.cpp +++ b/qthelper.cpp @@ -22,6 +22,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -407,3 +411,69 @@ extern "C" char * hashstring(char * filename) { return MainWindow::instance()->hashOf[QString(filename)].toHex().data(); } + +void read_hashes() +{ + QFile hashfile(QString(system_default_directory()).append("/hashes")); + qDebug() << QString(system_default_directory()).append("/hashes"); + if (hashfile.open(QIODevice::ReadOnly)) { + QDataStream stream(&hashfile); + stream >> MainWindow::instance()->localFilenameOf; + hashfile.close(); + } +} + +void write_hashes() +{ + QSaveFile hashfile(QString(system_default_directory()).append("/hashes")); + if (hashfile.open(QIODevice::WriteOnly)) { + QDataStream stream(&hashfile); + stream << MainWindow::instance()->localFilenameOf; + hashfile.commit(); + } else { + qDebug() << "cannot open" << hashfile.fileName(); + } +} + +QByteArray hashFile(const char *filename) +{ + QCryptographicHash hash(QCryptographicHash::Sha1); + QFile imagefile(filename); + imagefile.open(QIODevice::ReadOnly); + hash.addData(&imagefile); + return hash.result(); +} + +void updateHash(struct picture *picture) { + char *old = picture->hash; + picture->hash = strdup(hashFile(MainWindow::instance()->localFilenameOf[QByteArray::fromHex(picture->hash)].toUtf8().data()).toHex()); + free(old); +} + +void learnImage(const QByteArray filename) +{ + MainWindow::instance()->localFilenameOf[hashFile(filename.data())] = strdup(filename.data()); +} + +void learnImages(const QDir &dir, int maxdepth) +{ + QDir current(dir); + QList files; + QStringList filters; + + if (maxdepth) { + foreach (QString dirname, dir.entryList(QStringList(), QDir::NoDotAndDotDot | QDir::Dirs)) { + learnImages(QDir(dir.filePath(dirname)), maxdepth - 1); + } + } + + foreach (QString format, QImageReader::supportedImageFormats()) { + filters.append(QString("*.").append(format)); + } + + foreach (QString file, dir.entryList(filters, QDir::Files)) { + files.append(dir.absoluteFilePath(file).toUtf8()); + } + + QtConcurrent::blockingMap(files, learnImage); +} diff --git a/qthelper.h b/qthelper.h index 61e968c..3826efa 100644 --- a/qthelper.h +++ b/qthelper.h @@ -7,6 +7,7 @@ #include "dive.h" #include "divelist.h" #include +#include // global pointers for our translation extern QTranslator *qtTranslator, *ssrfTranslator; @@ -16,4 +17,9 @@ bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_te extern "C" const char *printGPSCoords(int lat, int lon); QList getDivesInTrip(dive_trip_t *trip); QString gasToStr(struct gasmix gas); +void read_hashes(); +void write_hashes(); +void updateHash(struct picture *picture); +QByteArray hashFile(const char *filename); +void learnImages(const QDir &dir, int maxdepth); #endif // QTHELPER_H -- 1.9.3 (Apple Git-50)