| 535 | } |
| 536 | |
| 537 | Task<void> ImageData::ensureValid(string_view channelSelector, int taskPriority) { |
| 538 | tlog::debug("Ensuring image is valid..."); |
| 539 | |
| 540 | if (channels.empty()) { |
| 541 | throw ImageLoadError{"Image must have at least one channel."}; |
| 542 | } |
| 543 | |
| 544 | // No data window? Default to the channel size |
| 545 | if (!dataWindow.isValid()) { |
| 546 | dataWindow = channels.front().size(); |
| 547 | } |
| 548 | |
| 549 | if (!displayWindow.isValid()) { |
| 550 | displayWindow = channels.front().size(); |
| 551 | } |
| 552 | |
| 553 | unordered_map<string_view, size_t> channelNameCounter; |
| 554 | for (auto& c : channels) { |
| 555 | if (c.size() != size()) { |
| 556 | throw ImageLoadError{ |
| 557 | fmt::format("All channels must have the same size as the data window. ({}: {} != {})", c.name(), c.size(), size()) |
| 558 | }; |
| 559 | } |
| 560 | |
| 561 | // Ensure the top-level layer of each channel is the image's part name |
| 562 | if (!c.name().starts_with(partName)) { |
| 563 | c.setName(Channel::joinIfNonempty(partName, c.name())); |
| 564 | } |
| 565 | |
| 566 | // Deduplicate channel names by appending a numeric suffix to their head (before the last dot). |
| 567 | // E.g.: foo.bar.R -> foo.bar.1.R, R -> 1.R |
| 568 | const size_t count = channelNameCounter[c.name()]++; |
| 569 | if (count > 0) { |
| 570 | c.setName(Channel::join(fmt::format("{}{}", Channel::head(c.name()), to_string(count)), Channel::tail(c.name()))); |
| 571 | tlog::debug("Renamed duplicate channel to '{}'", c.name()); |
| 572 | } |
| 573 | } |
| 574 | |
| 575 | if (!channelSelector.empty()) { |
| 576 | vector<pair<size_t, size_t>> matches; |
| 577 | for (size_t i = 0; i < channels.size(); ++i) { |
| 578 | size_t matchId; |
| 579 | if (matchesFuzzy(channels[i].name(), channelSelector, &matchId)) { |
| 580 | matches.emplace_back(matchId, i); |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | sort(begin(matches), end(matches)); |
| 585 | |
| 586 | // Prune and sort channels by the channel selector |
| 587 | vector<Channel> tmp = std::move(channels); |
| 588 | channels.clear(); |
| 589 | |
| 590 | for (const auto& match : matches) { |
| 591 | channels.emplace_back(std::move(tmp[match.second])); |
| 592 | } |
| 593 | } |
| 594 |
no test coverage detected