summaryrefslogtreecommitdiff
path: root/media/libjxl/src/tools/viewer/viewer_window.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/libjxl/src/tools/viewer/viewer_window.cc')
-rw-r--r--media/libjxl/src/tools/viewer/viewer_window.cc130
1 files changed, 130 insertions, 0 deletions
diff --git a/media/libjxl/src/tools/viewer/viewer_window.cc b/media/libjxl/src/tools/viewer/viewer_window.cc
new file mode 100644
index 0000000000..530c2f0141
--- /dev/null
+++ b/media/libjxl/src/tools/viewer/viewer_window.cc
@@ -0,0 +1,130 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "tools/viewer/viewer_window.h"
+
+#include <QElapsedTimer>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QKeyEvent>
+#include <QMessageBox>
+#include <QSet>
+
+#include "tools/icc_detect/icc_detect.h"
+#include "tools/viewer/load_jxl.h"
+
+namespace jxl {
+
+namespace {
+
+template <typename Output>
+void recursivelyAddSubEntries(const QFileInfo& info,
+ QSet<QString>* const visited,
+ Output* const output) {
+ if (visited->contains(info.absoluteFilePath())) return;
+ *visited << info.absoluteFilePath();
+ if (info.isDir()) {
+ QDir dir(info.absoluteFilePath());
+ for (const QFileInfo& entry : dir.entryInfoList(
+ QStringList() << "*.jxl",
+ QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot)) {
+ recursivelyAddSubEntries(entry, visited, output);
+ }
+ } else {
+ *output << info.absoluteFilePath();
+ }
+}
+
+} // namespace
+
+ViewerWindow::ViewerWindow(QWidget* const parent)
+ : QMainWindow(parent), monitorProfile_(GetMonitorIccProfile(this)) {
+ ui_.setupUi(this);
+ ui_.actionOpen->setShortcut(QKeySequence::Open);
+ ui_.actionExit->setShortcut(QKeySequence::Quit);
+}
+
+void ViewerWindow::loadFilesAndDirectories(QStringList entries) {
+ filenames_.clear();
+ QSet<QString> visited;
+ for (const QString& entry : entries) {
+ recursivelyAddSubEntries(entry, &visited, &filenames_);
+ }
+
+ const bool several = filenames_.size() > 1;
+ ui_.actionPreviousImage->setEnabled(several);
+ ui_.actionNextImage->setEnabled(several);
+
+ currentFileIndex_ = 0;
+ refreshImage();
+}
+
+void ViewerWindow::on_actionOpen_triggered() {
+ QFileDialog dialog(this, tr("Select JPEG XL files to open…"));
+ dialog.setFileMode(QFileDialog::ExistingFiles);
+ dialog.setNameFilter(tr("JPEG XL images (*.jxl);;All files (*)"));
+ if (dialog.exec()) {
+ loadFilesAndDirectories(dialog.selectedFiles());
+ }
+}
+
+void ViewerWindow::on_actionPreviousImage_triggered() {
+ currentFileIndex_ =
+ (currentFileIndex_ - 1 + filenames_.size()) % filenames_.size();
+ refreshImage();
+}
+
+void ViewerWindow::on_actionNextImage_triggered() {
+ currentFileIndex_ = (currentFileIndex_ + 1) % filenames_.size();
+ refreshImage();
+}
+
+void ViewerWindow::refreshImage() {
+ if (currentFileIndex_ < 0 || currentFileIndex_ >= filenames_.size()) {
+ return;
+ }
+
+ qint64 elapsed_ns;
+ bool usedRequestedProfile;
+ const QImage image =
+ loadJxlImage(filenames_[currentFileIndex_], monitorProfile_, &elapsed_ns,
+ &usedRequestedProfile);
+ if (image.isNull()) {
+ const QString message =
+ tr("Failed to load \"%1\".").arg(filenames_[currentFileIndex_]);
+ ui_.image->clear();
+ ui_.statusBar->showMessage(message);
+ QMessageBox errorDialog(this);
+ errorDialog.setIcon(QMessageBox::Critical);
+ errorDialog.setWindowTitle(tr("Failed to load image"));
+ errorDialog.setText(message);
+ errorDialog.exec();
+ return;
+ }
+
+ ui_.image->setPixmap(QPixmap::fromImage(image));
+ ui_.statusBar->showMessage(
+ tr("Loaded image %L1/%L2 (%3, %4×%5) in %L6ms (%L7 fps)")
+ .arg(currentFileIndex_ + 1)
+ .arg(filenames_.size())
+ .arg(filenames_[currentFileIndex_])
+ .arg(image.width())
+ .arg(image.height())
+ .arg(elapsed_ns / 1e6)
+ .arg(1e9 / elapsed_ns));
+
+ if (!usedRequestedProfile && !hasWarnedAboutMonitorProfile_) {
+ hasWarnedAboutMonitorProfile_ = true;
+ QMessageBox message(this);
+ message.setIcon(QMessageBox::Warning);
+ message.setWindowTitle(tr("No valid monitor profile found"));
+ message.setText(
+ tr("Failed to find a usable monitor profile. Images will be shown "
+ "assuming that the monitor's colorspace is sRGB."));
+ message.exec();
+ }
+}
+
+} // namespace jxl