viewer: load user mask from TIFF (replace or add)

Two Mask-menu entries read a 16-bit TIFF (via ReadTIFFFromString16) and
apply it as the user mask: "replace" overwrites the current mask, "add"
unions the TIFF into it. The TIFF must match the detector dimensions; any
non-zero pixel masks. Both go through UpdateUserMask_i like the other
mask edits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:52:21 +02:00
co-authored by Claude Opus 4.8
parent b2c60dfbd0
commit fef9c2f4c3
5 changed files with 61 additions and 0 deletions
+36
View File
@@ -3,6 +3,8 @@
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iterator>
#include "../common/JFJochMath.h"
#ifndef _WIN32
#include <sys/stat.h>
@@ -747,6 +749,40 @@ void JFJochImageReadingWorker::SaveUserMaskTIFF(QString filename) {
WriteTIFFToFile(filename.toStdString(), mask_image);
}
void JFJochImageReadingWorker::LoadUserMaskTIFF(QString filename, bool replace) {
QMutexLocker locker(&m);
if (!current_image_ptr)
return;
std::ifstream f(filename.toStdString(), std::ios::binary);
const std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
uint32_t cols = 0, lines = 0;
std::vector<uint16_t> tiff;
try {
tiff = ReadTIFFFromString16(content, cols, lines);
} catch (const std::exception &e) {
logger.Error("Could not read mask TIFF {}: {}", filename.toStdString(), e.what());
return;
}
const int64_t width = current_image_ptr->Dataset().experiment.GetXPixelsNum();
const int64_t height = current_image_ptr->Dataset().experiment.GetYPixelsNum();
if (static_cast<int64_t>(cols) != width || static_cast<int64_t>(lines) != height) {
logger.Error("Mask TIFF is {}x{} but the detector is {}x{}", cols, lines, width, height);
return;
}
// replace: start from an empty mask; add: keep the current one. A non-zero TIFF pixel masks.
auto user_mask = replace ? std::vector<uint32_t>(width * height, 0)
: current_image_ptr->Dataset().pixel_mask.GetUserMask();
for (size_t i = 0; i < tiff.size(); i++)
if (tiff[i] != 0)
user_mask[i] = 1;
UpdateUserMask_i(user_mask);
}
void JFJochImageReadingWorker::UploadUserMask() {
QMutexLocker locker(&m);
if (!current_image_ptr)
+1
View File
@@ -175,6 +175,7 @@ public slots:
void UploadROIsToServer();
void SaveUserMaskTIFF(QString filename);
void LoadUserMaskTIFF(QString filename, bool replace);
void UploadUserMask();
void ClearUserMask();
+17
View File
@@ -44,6 +44,12 @@ JFJochViewerMenu::JFJochViewerMenu(QWidget *parent) : QMenuBar(parent) {
const QAction *saveMaskTiff = maskMenu->addAction("Save User Mask as TIFF...");
connect(saveMaskTiff, &QAction::triggered, this, &JFJochViewerMenu::saveUserMaskAsTiffSelected);
const QAction *loadMaskReplace = maskMenu->addAction("Load User Mask from TIFF (replace)...");
connect(loadMaskReplace, &QAction::triggered, [this] { openLoadUserMaskTiff(true); });
const QAction *loadMaskAdd = maskMenu->addAction("Load User Mask from TIFF (add)...");
connect(loadMaskAdd, &QAction::triggered, [this] { openLoadUserMaskTiff(false); });
const QAction *uploadMask = maskMenu->addAction("&Upload User Mask");
connect(uploadMask, &QAction::triggered, this, &JFJochViewerMenu::uploadUserMaskAction);
@@ -185,6 +191,17 @@ void JFJochViewerMenu::saveUserMaskAsTiffSelected() {
}
}
void JFJochViewerMenu::openLoadUserMaskTiff(bool replace) {
QString filename = QFileDialog::getOpenFileName(
this,
replace ? "Load User Mask from TIFF (replace)" : "Load User Mask from TIFF (add)",
"",
"TIFF Images (*.tif *.tiff);;All Files (*)"
);
if (!filename.isEmpty())
emit loadUserMaskTiffSelected(filename, replace);
}
void JFJochViewerMenu::uploadUserMaskAction() {
auto reply = QMessageBox::question(
this,
+4
View File
@@ -28,6 +28,7 @@ signals:
void fileCloseSelected();
void saveUserMaskTiffSelected(const QString &filename);
void loadUserMaskTiffSelected(const QString &filename, bool replace);
void uploadUserMaskSelected();
void clearUserMaskSelected();
void openDatasetInfo();
@@ -41,4 +42,7 @@ private slots:
void saveUserMaskAsTiffSelected();
void uploadUserMaskAction();
private:
void openLoadUserMaskTiff(bool replace);
};
+3
View File
@@ -208,6 +208,9 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
connect(menuBar, &JFJochViewerMenu::saveUserMaskTiffSelected,
reading_worker, &JFJochImageReadingWorker::SaveUserMaskTIFF);
connect(menuBar, &JFJochViewerMenu::loadUserMaskTiffSelected,
reading_worker, &JFJochImageReadingWorker::LoadUserMaskTIFF);
connect(menuBar, &JFJochViewerMenu::uploadUserMaskSelected,
reading_worker, &JFJochImageReadingWorker::UploadUserMask);