| 1473 | } |
| 1474 | |
| 1475 | Task<ImageLoadResult> tryLoadImage( |
| 1476 | int taskPriority, fs::path path, istream& iStream, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels |
| 1477 | ) { |
| 1478 | // No need to keep loading images if tev is already shutting down again. |
| 1479 | if (shuttingDown()) { |
| 1480 | co_return {}; |
| 1481 | } |
| 1482 | |
| 1483 | const auto name = channelSelector.empty() ? toString(path) : fmt::format("{}:{}", toString(path), channelSelector); |
| 1484 | |
| 1485 | try { |
| 1486 | const auto start = chrono::system_clock::now(); |
| 1487 | |
| 1488 | if (!iStream) { |
| 1489 | throw ImageLoadError{fmt::format("Image {} could not be opened.", path)}; |
| 1490 | } |
| 1491 | |
| 1492 | fs::file_time_type fileLastModified = fs::file_time_type::clock::now(); |
| 1493 | if (fs::exists(path)) { |
| 1494 | // Unlikely, but the file could have been deleted, moved, or something else might have happened to it that makes obtaining its |
| 1495 | // last modified time impossible. Ignore such errors. |
| 1496 | try { |
| 1497 | fileLastModified = fs::last_write_time(path); |
| 1498 | } catch (...) {} |
| 1499 | } |
| 1500 | |
| 1501 | string loadMethod; |
| 1502 | vector<ImageData> imageData; |
| 1503 | bool success = false; |
| 1504 | for (const auto& imageLoader : ImageLoader::getLoaders()) { |
| 1505 | try { |
| 1506 | loadMethod = imageLoader->name(); |
| 1507 | imageData = co_await imageLoader->load(iStream, path, channelSelector, settings, taskPriority); |
| 1508 | success = true; |
| 1509 | break; |
| 1510 | } catch (const ImageLoader::FormatNotSupported& e) { |
| 1511 | tlog::debug("Image loader {} does not support loading {}: {} Trying next loader.", loadMethod, path, e.what()); |
| 1512 | |
| 1513 | // Reset file cursor to beginning and try next loader. |
| 1514 | iStream.clear(); |
| 1515 | iStream.seekg(0); |
| 1516 | } |
| 1517 | } |
| 1518 | |
| 1519 | if (!success) { |
| 1520 | throw ImageLoadError{"No suitable image loader found."}; |
| 1521 | } |
| 1522 | |
| 1523 | const auto makeImage = [&](ImageData& i) -> Task<shared_ptr<Image>> { |
| 1524 | co_await i.ensureValid(channelSelector, taskPriority); |
| 1525 | |
| 1526 | // If *multiple* image "parts" were loaded and they have names, ensure that these names are present in the channel selector. If |
| 1527 | // there's just a single part, it'll already be represented in the image's top-level layer name, so no need to clutter the UI by |
| 1528 | // explicitly listing it. |
| 1529 | string localChannelSelector; |
| 1530 | if (i.partName.empty() || imageData.size() == 1) { |
| 1531 | localChannelSelector = string{channelSelector}; |
| 1532 | } else { |
no test coverage detected