libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

test_window.cc (6979B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "tools/flicker_test/test_window.h"
      7 
      8 #include <QDir>
      9 #include <QMessageBox>
     10 #include <QSet>
     11 #include <algorithm>
     12 #include <random>
     13 
     14 #include "tools/icc_detect/icc_detect.h"
     15 
     16 namespace jpegxl {
     17 namespace tools {
     18 
     19 FlickerTestWindow::FlickerTestWindow(FlickerTestParameters parameters,
     20                                      QWidget* const parent)
     21     : QMainWindow(parent),
     22       monitorProfile_(GetMonitorIccProfile(this)),
     23       parameters_(std::move(parameters)),
     24       originalFolder_(parameters_.originalFolder, "*.png"),
     25       alteredFolder_(parameters_.alteredFolder, "*.png"),
     26       outputFile_(parameters_.outputFile) {
     27   ui_.setupUi(this);
     28   ui_.splitView->setSpacing(parameters_.spacing);
     29   ui_.endLabel->setText(
     30       tr("The test is complete and the results have been saved to \"%1\".")
     31           .arg(parameters_.outputFile));
     32   connect(ui_.startButton, &QAbstractButton::clicked, [&] {
     33     ui_.stackedView->setCurrentWidget(ui_.splitView);
     34     nextImage();
     35   });
     36   connect(ui_.splitView, &SplitView::testResult, this,
     37           &FlickerTestWindow::processTestResult);
     38 
     39   if (!outputFile_.open(QIODevice::WriteOnly)) {
     40     QMessageBox messageBox;
     41     messageBox.setIcon(QMessageBox::Critical);
     42     messageBox.setStandardButtons(QMessageBox::Close);
     43     messageBox.setWindowTitle(tr("Failed to open output file"));
     44     messageBox.setInformativeText(
     45         tr("Could not open \"%1\" for writing.").arg(outputFile_.fileName()));
     46     messageBox.exec();
     47     proceed_ = false;
     48     return;
     49   }
     50   outputStream_.setDevice(&outputFile_);
     51   outputStream_ << "image name,original side,clicked side,click delay (ms)\n";
     52 
     53   if (monitorProfile_.isEmpty()) {
     54     QMessageBox messageBox;
     55     messageBox.setIcon(QMessageBox::Warning);
     56     messageBox.setStandardButtons(QMessageBox::Ok);
     57     messageBox.setWindowTitle(tr("No monitor profile found"));
     58     messageBox.setText(
     59         tr("No ICC profile appears to be associated with the display. It will "
     60            "be assumed to match sRGB."));
     61     messageBox.exec();
     62   }
     63 
     64   originalFolder_.setFilter(QDir::Files);
     65   alteredFolder_.setFilter(QDir::Files);
     66 
     67 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
     68   auto originalImages = QSet<QString>::fromList(originalFolder_.entryList());
     69   auto alteredImages = QSet<QString>::fromList(alteredFolder_.entryList());
     70 #else
     71   const QStringList originalFolderEntries = originalFolder_.entryList();
     72   QSet<QString> originalImages(originalFolderEntries.begin(),
     73                                originalFolderEntries.end());
     74   const QStringList alteredFolderEntries = alteredFolder_.entryList();
     75   QSet<QString> alteredImages(alteredFolderEntries.begin(),
     76                               alteredFolderEntries.end());
     77 #endif
     78 
     79   auto onlyOriginal = originalImages - alteredImages;
     80   auto onlyAltered = alteredImages - originalImages;
     81   if (!onlyOriginal.isEmpty() || !onlyAltered.isEmpty()) {
     82     QMessageBox messageBox;
     83     messageBox.setIcon(QMessageBox::Warning);
     84     messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
     85     messageBox.setWindowTitle(tr("Image set mismatch"));
     86     messageBox.setText(
     87         tr("A mismatch has been detected between the original and altered "
     88            "images."));
     89     messageBox.setInformativeText(tr("Proceed with the test?"));
     90     QStringList detailedTextParagraphs;
     91     const QString itemFormat = tr("— %1\n");
     92     if (!onlyOriginal.isEmpty()) {
     93       QString originalList;
     94       for (const QString& original : onlyOriginal) {
     95         originalList += itemFormat.arg(original);
     96       }
     97       detailedTextParagraphs << tr("The following images were only found in "
     98                                    "the originals folder:\n%1")
     99                                     .arg(originalList);
    100     }
    101     if (!onlyAltered.isEmpty()) {
    102       QString alteredList;
    103       for (const QString& altered : onlyAltered) {
    104         alteredList += itemFormat.arg(altered);
    105       }
    106       detailedTextParagraphs << tr("The following images were only found in "
    107                                    "the altered images folder:\n%1")
    108                                     .arg(alteredList);
    109     }
    110     messageBox.setDetailedText(detailedTextParagraphs.join("\n\n"));
    111     if (messageBox.exec() == QMessageBox::Cancel) {
    112       proceed_ = false;
    113       return;
    114     }
    115   }
    116 
    117   remainingImages_ = originalImages.intersect(alteredImages).values();
    118   std::random_device rd;
    119   std::mt19937 g(rd());
    120   std::shuffle(remainingImages_.begin(), remainingImages_.end(), g);
    121 }
    122 
    123 void FlickerTestWindow::processTestResult(const QString& imageName,
    124                                           const SplitView::Side originalSide,
    125                                           const SplitView::Side clickedSide,
    126                                           const int clickDelayMSecs) {
    127   const auto sideToString = [](const SplitView::Side side) {
    128     switch (side) {
    129       case SplitView::Side::kLeft:
    130         return "left";
    131 
    132       case SplitView::Side::kRight:
    133         return "right";
    134     }
    135     return "unknown";
    136   };
    137   outputStream_ << imageName << "," << sideToString(originalSide) << ","
    138                 << sideToString(clickedSide) << "," << clickDelayMSecs << "\n";
    139 
    140   nextImage();
    141 }
    142 
    143 void FlickerTestWindow::nextImage() {
    144   if (remainingImages_.empty()) {
    145     outputStream_.flush();
    146     ui_.stackedView->setCurrentWidget(ui_.finalPage);
    147     return;
    148   }
    149   const QString image = remainingImages_.takeFirst();
    150 retry:
    151   QImage originalImage =
    152       loadImage(originalFolder_.absoluteFilePath(image), monitorProfile_,
    153                 parameters_.intensityTarget);
    154   QImage alteredImage = loadImage(alteredFolder_.absoluteFilePath(image),
    155                                   monitorProfile_, parameters_.intensityTarget);
    156   if (originalImage.isNull() || alteredImage.isNull()) {
    157     QMessageBox messageBox(this);
    158     messageBox.setIcon(QMessageBox::Warning);
    159     messageBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Ignore |
    160                                   QMessageBox::Abort);
    161     messageBox.setWindowTitle(tr("Failed to load image"));
    162     messageBox.setText(tr("Could not load image \"%1\".").arg(image));
    163     switch (messageBox.exec()) {
    164       case QMessageBox::Retry:
    165         goto retry;
    166 
    167       case QMessageBox::Ignore:
    168         outputStream_ << image << ",,,\n";
    169         nextImage();
    170         return;
    171 
    172       case QMessageBox::Abort:
    173         ui_.stackedView->setCurrentWidget(ui_.finalPage);
    174         return;
    175     }
    176   }
    177 
    178   ui_.splitView->setOriginalImage(std::move(originalImage));
    179   ui_.splitView->setAlteredImage(std::move(alteredImage));
    180   ui_.splitView->startTest(
    181       image, parameters_.blankingTimeMSecs, parameters_.viewingTimeSecs,
    182       parameters_.advanceTimeMSecs, parameters_.gray,
    183       parameters_.grayFadingTimeMSecs, parameters_.grayTimeMSecs);
    184 }
    185 
    186 }  // namespace tools
    187 }  // namespace jpegxl