472{
473 auto resolved = std::filesystem::path(
resolve_path(path.string()));
474 if (!std::filesystem::exists(resolved)) {
476 "Image file not found: {}", resolved.string());
477 return std::nullopt;
478 }
479
480 std::ifstream file(resolved, std::ios::binary | std::ios::ate);
481 if (!file.is_open()) {
483 "Failed to open image file: {}", resolved.string());
484 return std::nullopt;
485 }
486
487 std::streamsize file_size = file.tellg();
488 file.seekg(0, std::ios::beg);
489
490 std::vector<unsigned char> file_buffer(file_size);
491 if (!file.read(reinterpret_cast<char*>(file_buffer.data()), file_size)) {
493 "Failed to read image file: {}", resolved.string());
494 return std::nullopt;
495 }
496 file.close();
497
498 if (extension_of(resolved) == "exr") {
499 (void)desired_channels;
500 auto image = load_exr_from_memory(file_buffer.data(),
static_cast<size_t>(file_size));
501 if (
image && region) {
502 return crop_image(*
image, *region);
503 }
505 }
506
508
509 if (desired_channels == 0) {
510 stbi_info_from_memory(file_buffer.data(), static_cast<int>(file_buffer.size()),
513 desired_channels = 4;
514 }
515 }
516
517 unsigned char*
pixels = stbi_load_from_memory(
518 file_buffer.data(),
519 static_cast<int>(file_buffer.size()),
521 desired_channels);
522
525 "Failed to decode image: {} - {}",
526 path.string(), stbi_failure_reason());
527 return std::nullopt;
528 }
529
530 int result_channels = (desired_channels != 0) ? desired_channels :
channels;
531
533 "Loaded image: {} ({}x{}, {} channels{})",
534 resolved.filename().string(),
width,
height, result_channels,
535 (
channels == 3 && result_channels == 4) ?
" [RGB→RGBA]" :
"");
536
538 auto& buf = result.
pixels.emplace<std::vector<uint8_t>>();
539 size_t data_size =
static_cast<size_t>(
width) *
height * result_channels;
540 buf.resize(data_size);
541 std::memcpy(buf.data(),
pixels, data_size);
542
543 result.width =
width;
545 result.channels = result_channels;
546
547 switch (result_channels) {
548 case 1:
549 result.format = Portal::Graphics::ImageFormat::R8;
550 break;
551 case 2:
552 result.format = Portal::Graphics::ImageFormat::RG8;
553 break;
554 case 4:
555 result.format = Portal::Graphics::ImageFormat::RGBA8;
556 break;
557 default:
559 "Unsupported channel count: {}", result_channels);
561 return std::nullopt;
562 }
563
565 if (region) {
566 return crop_image(result, *region);
567 }
568 return result;
569}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
const std::vector< float > * pixels
static std::string resolve_path(const std::string &filepath)
Resolve a filepath against the project source root if not found as-is.
Kakshya::ImageData ImageData
@ FileIO
Filesystem I/O operations.
@ IO
Networking, file handling, streaming.