Load source images in the background with a progress window
Decoding a batch of photographs took seconds on the main thread, so the window froze with no sign of what was happening. loadImages now takes an optional LoadProgress (per-file callback plus a cancel flag) and hands files out from a shared cursor, so one large file cannot stall the queue behind it. The GUI decodes off the main thread and shows a progress window with the count, the current file and a Cancel button; it only appears if the batch is still running after 250 ms. Headless mode keeps a "reading n/total" line on stderr when it is attached to a terminal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
// Small self-contained checks for the pieces that have no GUI dependency.
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -144,6 +146,47 @@ int main() {
|
||||
check(threw, "missing file throws");
|
||||
}
|
||||
|
||||
std::cout << "batch loading\n";
|
||||
{
|
||||
const auto dir = std::filesystem::temp_directory_path() / "effector_test_batch";
|
||||
std::filesystem::create_directories(dir);
|
||||
std::vector<std::string> paths;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
const auto path = dir / ("src" + std::to_string(i) + ".png");
|
||||
gradient(32, 24, i + 1).save(path.string());
|
||||
paths.push_back(path.string());
|
||||
}
|
||||
paths.push_back((dir / "missing.png").string());
|
||||
|
||||
std::atomic<std::size_t> calls{0};
|
||||
std::size_t lastTotal = 0;
|
||||
std::mutex mutex;
|
||||
LoadProgress progress;
|
||||
progress.onFile = [&](std::size_t done, std::size_t total, const std::string&) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
++calls;
|
||||
lastTotal = total;
|
||||
check(done >= 1 && done <= total, "progress step is within the batch");
|
||||
};
|
||||
|
||||
std::vector<LoadFailure> failuresOut;
|
||||
const auto images = loadImages(paths, failuresOut, &progress);
|
||||
check(images.size() == 6, "every readable image is returned");
|
||||
check(failuresOut.size() == 1, "the unreadable one is reported");
|
||||
check(calls.load() == paths.size(), "progress fires once per file");
|
||||
check(lastTotal == paths.size(), "progress reports the batch size");
|
||||
check(images.front().path() == paths.front(), "input order is preserved");
|
||||
|
||||
std::atomic<bool> cancel{true};
|
||||
LoadProgress cancelled;
|
||||
cancelled.cancel = &cancel;
|
||||
std::vector<LoadFailure> ignored;
|
||||
const auto none = loadImages(paths, ignored, &cancelled);
|
||||
check(none.empty(), "a cancelled batch loads nothing");
|
||||
|
||||
std::filesystem::remove_all(dir);
|
||||
}
|
||||
|
||||
std::cout << (failures == 0 ? "\nall checks passed\n" : "\n" + std::to_string(failures) + " failed\n");
|
||||
return failures == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user