AcademySoftwareFoundation / OpenImageIO

Reading, writing, and processing images in a wide variety of file formats, using a format-agnostic API, aimed at VFX applications.
https://openimageio.readthedocs.org
Apache License 2.0
1.99k stars 602 forks source link

[FEATURE REQUEST] IOProxy read from memory without valid file #4547

Open EmilDohne opened 1 day ago

EmilDohne commented 1 day ago

Is your feature request related to a problem? Please describe. I'm currently implementing smart objects into my Photoshop reader/writer API and those (sometimes) store the raw file bytes directly in memory rather than having a file on disk it references. From what I can tell though OpenImageIO requires a valid filepath to read from an IOProxy. I've thrown together a hacky solution that works but it requires a temporary file to be created in order to actually read the file.

If there is a way to do this natively feel free to point me to it and I'll close this ticket :)

namespace _Impl
{
  struct TempImageFile
  {

    TempImageFile(std::filesystem::path file_path)
    {
      m_FilePath = file_path;
      std::unique_ptr<OIIO::ImageOutput> out = OIIO::ImageOutput::create(file_path);
      if (!out)
          return;  // error

      std::vector<uint8_t> pixels(1);
      OIIO::ImageSpec spec(1, 1, 1, OIIO::TypeDesc::UINT8);
      out->open(file_path, spec);
      out->write_image(OIIO::TypeDesc::UINT8, pixels.data());
      out->close();
    }

    ~TempImageFile()
    {
      std::filesystem::remove(m_FilePath);
    }

  private:
      std::filesystem::path m_FilePath;
  };
}

int main()
{
  std::filesystem::path file_path; // ....
  std::vector<std::byte> raw_data; // ...

  _Impl::TempImageFile tmp_file(file_path);
  auto _in = OIIO::ImageInput::create(file_path);
  if (_in && static_cast<bool>(_in->supports("ioproxy")))
  {
      OIIO::Filesystem::IOMemReader memreader(raw_data.data(), raw_data.size());
      auto oiio_in = OIIO::ImageInput::open(file_path.string(), nullptr, &memreader);
      // keep processing.
  }
}

Describe the solution you'd like A way to create an imageinput purely from memory.

Describe alternatives you've considered I looked into using an OIIO::ImageBuf for this purpose but it looked like it only supported being backed from pixel buffers? Unsure about this.

jessey-git commented 1 day ago

The ceremonial API dance I do for this case is the following:

  // During create(), provide _just_ the format extension (psd here) that OIIO will recognize
  // It will perform a stat/existence check on the "file" but no further filesystem access should occur.
  unique_ptr<ImageInput> in = ImageInput::create("psd");
  if (!in) {
    return nullptr;
  }

  // Set the ioproxy and use empty "" path during open()
  in->set_ioproxy(&mem_reader);
  bool ok = in->open("", newspec, config);
  ...
EmilDohne commented 1 day ago

Ah thats smart! I wasnt aware you could do this, when I tried passing the filename or e.g. .exr in would be nullptr but I'll try what you suggested!