| 420 | } |
| 421 | |
| 422 | static void setupImageScan(CLI::App& image) |
| 423 | { |
| 424 | auto* cmd = image.add_subcommand("scan", "Scan a directory of textures for a black+white frame/border pattern"); |
| 425 | static std::string dir; |
| 426 | static int top = 25; |
| 427 | cmd->add_option("dir", dir, "Directory of textures (recursive; .paa/.pac)") |
| 428 | ->required() |
| 429 | ->check(CLI::ExistingDirectory); |
| 430 | cmd->add_option("--top", top, "Show this many top matches (default 25)"); |
| 431 | cmd->callback( |
| 432 | []() |
| 433 | { |
| 434 | namespace fs = std::filesystem; |
| 435 | struct Hit |
| 436 | { |
| 437 | std::string path; |
| 438 | int w, h; |
| 439 | double score, rb, rw; |
| 440 | }; |
| 441 | std::vector<Hit> hits; |
| 442 | int scanned = 0; |
| 443 | for (const auto& e : fs::recursive_directory_iterator(dir)) |
| 444 | { |
| 445 | if (!e.is_regular_file()) |
| 446 | continue; |
| 447 | std::string ext = e.path().extension().string(); |
| 448 | for (auto& c : ext) |
| 449 | c = (char)tolower((unsigned char)c); |
| 450 | if (ext != ".paa" && ext != ".pac") |
| 451 | continue; |
| 452 | Poseidon::DecodedImage img = Poseidon::DecodePAAFile(e.path().string()); |
| 453 | if (!img.valid()) |
| 454 | continue; |
| 455 | scanned++; |
| 456 | auto [score, rb, rw] = FrameBorderScore(img); |
| 457 | if (score > 0.02) |
| 458 | hits.push_back({e.path().string(), img.width, img.height, score, rb, rw}); |
| 459 | } |
| 460 | std::sort(hits.begin(), hits.end(), [](const Hit& a, const Hit& b) { return a.score > b.score; }); |
| 461 | std::cout << "Scanned " << scanned << " textures; " << hits.size() << " with a black+white border.\n\n"; |
| 462 | std::cout << std::left << std::setw(10) << "score" << std::setw(8) << "black" << std::setw(8) << "white" |
| 463 | << std::setw(11) << "size" << "texture\n"; |
| 464 | std::cout << std::string(90, '-') << "\n"; |
| 465 | int n = 0; |
| 466 | for (const auto& hit : hits) |
| 467 | { |
| 468 | if (n++ >= top) |
| 469 | break; |
| 470 | char sz[24]; |
| 471 | std::snprintf(sz, sizeof(sz), "%dx%d", hit.w, hit.h); |
| 472 | std::cout << std::left << std::fixed << std::setprecision(3) << std::setw(10) << hit.score |
| 473 | << std::setw(8) << hit.rb << std::setw(8) << hit.rw << std::setw(11) << sz << hit.path |
| 474 | << "\n"; |
| 475 | } |
| 476 | }); |
| 477 | } |
| 478 | |
| 479 | void ImageCommand::Setup(CLI::App& app) |
no test coverage detected