Skip to content

Feature/1187 Read EXR files from memory #1448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 69 additions & 9 deletions vtkext/private/module/vtkF3DEXRReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <ImfArray.h>
#include <ImfRgbaFile.h>

#include <cstring>
#include <sstream>
#include <thread>

Expand Down Expand Up @@ -38,13 +39,13 @@
this->ComputeInternalFileName(this->DataExtent[4]);
if (this->InternalFileName == nullptr || this->InternalFileName[0] == '\0')
{
return;
// If we have no file then maybe we have the file in memory
if (!this->MemoryBuffer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you put this check in the line above ?

return;
}

try
auto execute = [&](Imf::RgbaInputFile& file)
{
Imf::RgbaInputFile file(this->InternalFileName);

Imath::Box2i dw = file.dataWindow();
this->DataExtent[0] = dw.min.x;
this->DataExtent[1] = dw.max.x;
Expand All @@ -56,6 +57,21 @@
{
throw std::runtime_error("only RGB and RGBA channels are supported");
}
};

try
{
if (this->MemoryBuffer)
{
MemStream memoryStream("EXRmemoryStream", this->MemoryBuffer, this->MemoryBufferLength);
Imf::RgbaInputFile file = Imf::RgbaInputFile(memoryStream);
execute(file);

Check warning on line 68 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L66-L68

Added lines #L66 - L68 were not covered by tests
}
else
{
Imf::RgbaInputFile file(this->InternalFileName);
execute(file);
}
}
catch (const std::exception& e)
{
Expand Down Expand Up @@ -112,12 +128,8 @@
scalars->SetName("Pixels");
float* dataPtr = scalars->GetPointer(0);

try
auto execute = [&](Imf::RgbaInputFile& file)
{
assert(this->InternalFileName);
Imf::setGlobalThreadCount(std::thread::hardware_concurrency());
Imf::RgbaInputFile file(this->InternalFileName);

Imf::Array2D<Imf::Rgba> pixels(this->GetHeight(), this->GetWidth());

file.setFrameBuffer(&pixels[0][0], 1, this->GetWidth());
Expand All @@ -134,6 +146,24 @@
dataPtr += 3;
}
}
};

try
{
assert(this->InternalFileName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this assert should not be here for the memory stream part. BTW it may be better to make it an actual if test since we now can have an empty InteralFileName, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes when loading a USD scene the EXRReader will have an empty filename. Interestingly in the test case TestF3DEXRMemReader, If i omit the filename on line 33 I get an error in vtkImageReader2.cxx:111 for not setting a filename.

Imf::setGlobalThreadCount(std::thread::hardware_concurrency());

if (this->MemoryBuffer)
{
MemStream memoryStream("EXRmemoryStream", this->MemoryBuffer, this->MemoryBufferLength);
Imf::RgbaInputFile file = Imf::RgbaInputFile(memoryStream);
execute(file);

Check warning on line 160 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L158-L160

Added lines #L158 - L160 were not covered by tests
}
else
{
Imf::RgbaInputFile file(this->InternalFileName);
execute(file);
}
}
catch (const std::exception& e)
{
Expand All @@ -142,6 +172,24 @@
}
}

//------------------------------------------------------------------------------
/**
* Read from memory instead of file
*/
void vtkF3DEXRReader::SetMemoryBuffer(const void* buff)

Check warning on line 179 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L179

Added line #L179 was not covered by tests
{
this->MemoryBuffer = buff;

Check warning on line 181 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L181

Added line #L181 was not covered by tests
}

//------------------------------------------------------------------------------
/**
* Specify the in memory image buffer length.
*/
void vtkF3DEXRReader::SetMemoryBufferLength(vtkIdType bufferLen)

Check warning on line 188 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L188

Added line #L188 was not covered by tests
{
this->MemoryBufferLength = bufferLen;

Check warning on line 190 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L190

Added line #L190 was not covered by tests
}

//------------------------------------------------------------------------------
int vtkF3DEXRReader::GetWidth() const
{
Expand All @@ -153,3 +201,15 @@
{
return this->DataExtent[3] - this->DataExtent[2] + 1;
}

//------------------------------------------------------------------------------
bool vtkF3DEXRReader::MemStream::read(char c[], int n)

Check warning on line 206 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L206

Added line #L206 was not covered by tests
{
if (pos + n <= bufflen)

Check warning on line 208 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L208

Added line #L208 was not covered by tests
{
memcpy(c, buffer + pos, n);
pos += n;
return true;

Check warning on line 212 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L210-L212

Added lines #L210 - L212 were not covered by tests
}
return false;

Check warning on line 214 in vtkext/private/module/vtkF3DEXRReader.cxx

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.cxx#L214

Added line #L214 was not covered by tests
}
58 changes: 58 additions & 0 deletions vtkext/private/module/vtkF3DEXRReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "vtkImageReader.h"

#include <OpenEXR/ImfIO.h>

class vtkF3DEXRReader : public vtkImageReader
{
public:
Expand Down Expand Up @@ -31,6 +33,16 @@
return "OpenEXR";
}

/**
* Read from memory instead of file
*/
void SetMemoryBuffer(const void* buff) override;

/**
* Specify the in memory image buffer length.
*/
void SetMemoryBufferLength(vtkIdType buflen) override;

protected:
vtkF3DEXRReader();
~vtkF3DEXRReader() override;
Expand All @@ -44,6 +56,52 @@
private:
vtkF3DEXRReader(const vtkF3DEXRReader&) = delete;
void operator=(const vtkF3DEXRReader&) = delete;

/**
* Class to treat file contents in memory like it were still in a file.
*/
class MemStream : public Imf::IStream
{
public:
MemStream(const char* name, const void* buff, vtkIdType bufferLen)
: Imf::IStream(name)
, buffer(static_cast<const char*>(buff))
, bufflen(static_cast<size_t>(bufferLen))
, pos(0)

Check warning on line 70 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L66-L70

Added lines #L66 - L70 were not covered by tests
{
}

bool read(char c[], int n) override;

/**
* returns the current reading position, in bytes, from the beginning of the file.
* The next read() call will begin reading at the indicated position
*/
uint64_t tellg() override

Check warning on line 80 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L80

Added line #L80 was not covered by tests
{
return pos;

Check warning on line 82 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L82

Added line #L82 was not covered by tests
}

/**
* sets the current reading position to pos bytes from the beginning of the "file"
*/
void seekg(uint64_t new_pos) override

Check warning on line 88 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L88

Added line #L88 was not covered by tests
{
pos = new_pos;

Check warning on line 90 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L90

Added line #L90 was not covered by tests
}

/**
* clears any error flags (we dont have to worry about this)
*/
void clear() override

Check warning on line 96 in vtkext/private/module/vtkF3DEXRReader.h

View check run for this annotation

Codecov / codecov/patch

vtkext/private/module/vtkF3DEXRReader.h#L96

Added line #L96 was not covered by tests
{
}

private:
const char* buffer;
size_t bufflen;
uint64_t pos;
};
};

#endif
Loading