From f30dd2a5200988475a9daeda88b67a5dde784cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Mon, 17 Mar 2025 11:08:18 +0100 Subject: [PATCH] Add generating thumbnails from cmd line --- CMakeLists.txt | 1 + imageringlist.cpp | 22 +++++++++++---- imageringlist.h | 4 ++- main.cpp | 55 +++++++++++++++++++++++++++++++++--- mainwindow.cpp | 21 ++++---------- mainwindow.h | 3 +- thumbnailer/genthumbnail.cpp | 37 ++++++++++++++++++++++++ thumbnailer/genthumbnail.h | 8 ++++++ 8 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 thumbnailer/genthumbnail.cpp create mode 100644 thumbnailer/genthumbnail.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e69fb6..972930e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ set(TENMON_SRC stfslider.cpp stfslider.h stretchtoolbar.cpp stretchtoolbar.h tfloat16.h + thumbnailer/genthumbnail.cpp thumbnailer/genthumbnail.h ) qt_add_resources(TENMON_SRC resources/resources.qrc) diff --git a/imageringlist.cpp b/imageringlist.cpp index 8d4794e..00690be 100644 --- a/imageringlist.cpp +++ b/imageringlist.cpp @@ -113,6 +113,7 @@ ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, , m_analyzeLevel(None) , m_database(database) , m_nameFilter(nameFilter) + , m_fileSuffix(nameFilter) { connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString))); m_nameFilter.replaceInStrings(QRegularExpression("^"), "*."); @@ -170,8 +171,8 @@ bool ImageRingList::setDir(const QString path, const QString ¤tFile, bool }; scanDir(path); - qDebug() << absolutePaths.size(); - setFiles(absolutePaths, m_liveMode ? absolutePaths.first() : currentFile); + //qDebug() << absolutePaths.size(); + setFilesPrivate(absolutePaths, m_liveMode ? absolutePaths.first() : currentFile); m_fileSystemWatcher.removePaths(m_fileSystemWatcher.directories()); m_fileSystemWatcher.addPath(path); @@ -192,6 +193,17 @@ void ImageRingList::setFile(const QString &file) } } +void ImageRingList::setFiles(QStringList files) +{ + QRegularExpression reg("(" + m_fileSuffix.join("|") + ")"); + files.removeIf([®](const QString &file){ + QFileInfo info(file); + auto match = reg.match(info.suffix()); + return !match.hasMatch() || !info.exists() || !info.isReadable() || !info.isFile(); + }); + setFilesPrivate(files); +} + ImagePtr ImageRingList::currentImage() { if(m_images.size()) @@ -237,11 +249,11 @@ void ImageRingList::decrement() void ImageRingList::setMarked() { QStringList files = m_database->getMarkedFiles(); - std::remove_if(files.begin(), files.end(), [](const QString &file){ + files.removeIf([](const QString &file){ QFileInfo info(file); return !info.exists() || !info.isReadable(); }); - setFiles(files); + setFilesPrivate(files); } void ImageRingList::setLiveMode(bool live) @@ -474,7 +486,7 @@ void ImageRingList::toggleSlideshow(bool start) } } -void ImageRingList::setFiles(const QStringList files, const QString ¤tFile) +void ImageRingList::setFilesPrivate(const QStringList files, const QString ¤tFile) { m_loadPool->clear(); m_thumbPool->clear(); diff --git a/imageringlist.h b/imageringlist.h index d75efa5..b285ade 100644 --- a/imageringlist.h +++ b/imageringlist.h @@ -68,6 +68,7 @@ class ImageRingList : public QAbstractItemModel QThreadPool *m_thumbPool; Database *m_database; QStringList m_nameFilter; + QStringList m_fileSuffix; QTimer *m_slideShowTimer; QTimer *m_dirChangeDelay; QString m_currentDir; @@ -76,6 +77,7 @@ public: ~ImageRingList() override; bool setDir(const QString path, const QString ¤tFile = QString(), bool recursive = false); void setFile(const QString &file); + void setFiles(QStringList files); ImagePtr currentImage(); void setLiveMode(bool live); void setCalculateStats(bool stats); @@ -105,7 +107,7 @@ public slots: void decrement(); void setMarked(); protected: - void setFiles(const QStringList files, const QString ¤tFile = QString()); + void setFilesPrivate(const QStringList files, const QString ¤tFile = QString()); QList::iterator increment(QList::iterator iter); QList::iterator decrement(QList::iterator iter); signals: diff --git a/main.cpp b/main.cpp index d047101..8a71687 100644 --- a/main.cpp +++ b/main.cpp @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include "thumbnailer/genthumbnail.h" int main(int argc, char *argv[]) { @@ -15,12 +17,39 @@ int main(int argc, char *argv[]) #else bool useGLES = true; #endif + + QCommandLineParser cmd; + cmd.addOption({"gl", "Use desktop OpenGL. This is default on x86 and MacOS platform."}); + cmd.addOption({"gles", "Use OpenGL ES. This is default on ARM platform."}); + cmd.addOption({{"thumb", "thumbnail"}, "Generate thumbnail and save it to path.", "path"}); + cmd.addOption({{"s", "size"}, "Size of the thumbnails in pixels (default: 128)", "size", "128"}); + cmd.addPositionalArgument("file", "File to open"); + cmd.addHelpOption(); + QStringList cmdArgs; for(int i = 0; i < argc; i++) + cmdArgs.append(argv[i]); + + cmd.process(cmdArgs); + if(cmd.isSet("gl")) + useGLES = false; + if(cmd.isSet("gles")) + useGLES = true; + + if(cmd.isSet("thumb")) { - if(std::strcmp("-gl", argv[i]) == 0) - useGLES = false; - if(std::strcmp("-gles", argv[i]) == 0) - useGLES = true; + QCoreApplication app(argc, argv); + QStringList files = cmd.positionalArguments(); + if(files.size() == 0) + return 1; + + QString thumb = cmd.value("thumb"); + int size = 128; + bool ok; + int size2 = cmd.value("s").toInt(&ok); + if(ok) + size = size2; + + return generateThumbnail(files.front(), thumb, size); } QSurfaceFormat format; @@ -39,6 +68,7 @@ int main(int argc, char *argv[]) } QSurfaceFormat::setDefaultFormat(format); + QApplication a(argc, argv); a.setOrganizationName("nou"); a.setApplicationName("Tenmon"); @@ -54,5 +84,22 @@ int main(int argc, char *argv[]) MainWindow w; w.show(); + if(!cmd.positionalArguments().isEmpty()) + { + QStringList files = cmd.positionalArguments(); + QStringList paths; + for(auto &arg : files) + { + QUrl url(arg); + QFileInfo info(url.isLocalFile() ? url.toLocalFile() : arg); + if(info.exists()) + paths.append(info.canonicalFilePath()); + } + if(paths.size() == 1) + w.loadFile(paths.front()); + else if(paths.size() > 1) + w.loadFiles(paths); + } + return a.exec(); } diff --git a/mainwindow.cpp b/mainwindow.cpp index e00cda2..c8e8e6c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -327,22 +327,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) _lastDir = settings.value("mainwindow/lastdir", _lastDir).toString(); - QStringList args = QCoreApplication::arguments(); - args.removeFirst(); - for(auto &arg : args) - { - QUrl url(arg); - QFileInfo info(url.isLocalFile() ? url.toLocalFile() : arg); - if(info.exists()) - { - m_ringList->setFile(info.canonicalFilePath()); - updateWindowTitle(); - _lastDir = info.absoluteDir().absolutePath(); - settings.setValue("mainwindow/lastdir", _lastDir); - break; - } - } - m_image->setFocus(); // workaround for nasty wayland backend bug https://bugreports.qt.io/browse/QTBUG-87332 @@ -565,6 +549,11 @@ void MainWindow::loadFile(const QString &path) } } +void MainWindow::loadFiles(const QStringList &paths) +{ + m_ringList->setFiles(paths); +} + void MainWindow::loadFile(int row) { m_ringList->loadFile(row); diff --git a/mainwindow.h b/mainwindow.h index 63cf63f..57f2e56 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -41,11 +41,12 @@ protected: void closeEvent(QCloseEvent *event) override; void copyOrMove(bool copy); void copyOrMove(bool copy, const QString &dest); -protected slots: +public slots: void socketNotify(); void updateWindowTitle(); void loadFile(); void loadFile(const QString &path); + void loadFiles(const QStringList &paths); void loadFile(int row); void loadDir(); void indexDir(); diff --git a/thumbnailer/genthumbnail.cpp b/thumbnailer/genthumbnail.cpp new file mode 100644 index 0000000..9eeeb39 --- /dev/null +++ b/thumbnailer/genthumbnail.cpp @@ -0,0 +1,37 @@ +#include "genthumbnail.h" +#include "../rawimage.h" +#include "../loadimage.h" + + +int generateThumbnail(const QString &input, const QString &output, uint32_t size) +{ + ImageInfoData info; + std::shared_ptr rawImage; + if(!loadImage(input, info, rawImage)) + return 2; + + if(!rawImage) + return 3; + + QSize rect(rawImage->width(), rawImage->height()); + rect.scale(size, size, Qt::KeepAspectRatio); + rawImage->calcStats(); + rawImage->resize(rect.width(), rect.height()); + if(rawImage->imageStats().m_median[0] < rawImage->norm() * 0.2f) + { + MTFParam mtfParams = rawImage->calcMTFParams(true); + rawImage->applySTF(mtfParams); + } + rawImage->convertToType(RawImage::UINT8); + + QImage img; + if(rawImage->channels() == 1) + img = QImage((const uchar*)rawImage->data(), rawImage->width(), rawImage->height(), rawImage->widthBytes(), QImage::Format_Grayscale8); + else + img = QImage((const uchar*)rawImage->data(), rawImage->width(), rawImage->height(), rawImage->widthBytes(), QImage::Format_RGBA8888); + + if(!img.save(output, "png")) + return 4; + + return 0; +} diff --git a/thumbnailer/genthumbnail.h b/thumbnailer/genthumbnail.h new file mode 100644 index 0000000..e7fffe0 --- /dev/null +++ b/thumbnailer/genthumbnail.h @@ -0,0 +1,8 @@ +#ifndef GENTHUMBNAIL_H +#define GENTHUMBNAIL_H + +#include + +int generateThumbnail(const QString &input, const QString &output, uint32_t size); + +#endif // GENTHUMBNAIL_H