| 457 | } |
| 458 | |
| 459 | bool Bitmap::Read(const std::filesystem::path& path, |
| 460 | const bool as_rgb, |
| 461 | const bool linearize_colorspace) { |
| 462 | if (!ExistsFile(path)) { |
| 463 | VLOG(3) << "Failed to read bitmap, because file does not exist"; |
| 464 | return false; |
| 465 | } |
| 466 | |
| 467 | OIIO::ImageSpec config; |
| 468 | config["oiio:reorient"] = 0; |
| 469 | |
| 470 | const auto input = OIIO::ImageInput::open(PathToUtf8(path), &config); |
| 471 | if (!input) { |
| 472 | // Always retrieve the error to clear OIIO's pending error state. |
| 473 | const std::string error = OIIO::geterror(); |
| 474 | VLOG(3) << "Failed to read bitmap: " << error; |
| 475 | return false; |
| 476 | } |
| 477 | |
| 478 | const OIIO::ImageSpec& image_spec = input->spec(); |
| 479 | width_ = image_spec.width; |
| 480 | height_ = image_spec.height; |
| 481 | const int file_channels = image_spec.nchannels; |
| 482 | // Handle images with alpha channel by dropping alpha: |
| 483 | // - 4 channels (RGBA) -> 3 channels (RGB) |
| 484 | // - 2 channels (grayscale + alpha) -> 1 channel (grayscale) |
| 485 | if (file_channels == 4) { |
| 486 | channels_ = 3; |
| 487 | } else if (file_channels == 2) { |
| 488 | channels_ = 1; |
| 489 | } else if (file_channels == 1 || file_channels == 3) { |
| 490 | channels_ = file_channels; |
| 491 | } else { |
| 492 | VLOG(3) << "Unsupported number of channels: " << file_channels; |
| 493 | return false; |
| 494 | } |
| 495 | |
| 496 | data_.resize(width_ * height_ * channels_); |
| 497 | // Note that OIIO supports reading a subset of channels. |
| 498 | input->read_image(0, 0, 0, channels_, OIIO::TypeDesc::UINT8, data_.data()); |
| 499 | input->close(); |
| 500 | |
| 501 | auto meta_data = std::make_unique<OIIOMetaData>(); |
| 502 | meta_data->image_spec = image_spec; |
| 503 | meta_data->image_spec.nchannels = channels_; |
| 504 | meta_data_ = std::move(meta_data); |
| 505 | |
| 506 | if (linearize_colorspace) { |
| 507 | const std::string colorspace = image_spec["oiio:ColorSpace"]; |
| 508 | if (IsEquivalentColorSpace(colorspace, "linear")) { |
| 509 | data_ = ConvertColorSpace( |
| 510 | data_.data(), width_, height_, channels_, colorspace, "linear"); |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | if (as_rgb && channels_ != 3) { |
| 515 | *this = CloneAsRGB(); |
| 516 | } else if (!as_rgb && channels_ != 1) { |