-
-
Notifications
You must be signed in to change notification settings - Fork 205
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
Feature/1187 Read EXR files from memory #1448
base: master
Are you sure you want to change the base?
Changes from all commits
a9d19fa
ec8dc6c
e38c111
2e0ab33
35e9c9f
5f9ae1a
c4a65f0
6d66a8f
69dc5e8
d15f044
88622bc
4ea8564
a9a6c81
ef76977
82e2b40
767eec2
e513d7a
0f910f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include <vtkImageData.h> | ||
#include <vtkNew.h> | ||
|
||
#include "vtkF3DEXRReader.h" | ||
|
||
#include <fstream> | ||
#include <iostream> | ||
#include <vector> | ||
/** | ||
* image file taken from | ||
* https://github.com/AcademySoftwareFoundation/openexr/blob/370db2835843ac75f85e1386c05455f26a6ff58c/website/test_images/Chromaticities/Rec709.rst | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. im not sure how that .rst file is related to the .exr file ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the rst file is just a markdown file on github showing the exr file and it details. I just grabbed it because it was smaller than the other exr files in the repo which made the unit test run a but faster. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to just use an existing one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indeed, better to use an existing one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can remove this line, since you list it in data licenses now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please remove this line |
||
*/ | ||
bool readFileToVector(const std::string& filename, std::vector<char>& buffer) | ||
{ | ||
std::ifstream file(filename, std::ios::binary | std::ios::ate); | ||
if (!file) | ||
{ | ||
return false; | ||
} | ||
|
||
std::streamsize size = file.tellg(); | ||
file.seekg(0, std::ios::beg); | ||
buffer.resize(size); | ||
return file.read(buffer.data(), size) ? true : false; | ||
} | ||
|
||
int TestF3DEXRMemReader(int argc, char* argv[]) | ||
{ | ||
vtkNew<vtkF3DEXRReader> reader; | ||
|
||
std::string actual_filename = std::string(argv[1]) + "data/Rec709.exr"; | ||
std::string filename = "readFromMem.exr"; | ||
reader->SetFileName(filename.c_str()); | ||
std::vector<char> buff; | ||
readFileToVector(actual_filename, buff); | ||
reader->SetMemoryBuffer(buff.data()); | ||
reader->SetMemoryBufferLength(buff.size()); | ||
reader->Update(); | ||
|
||
reader->Print(cout); | ||
|
||
vtkImageData* img = reader->GetOutput(); | ||
|
||
int* dims = img->GetDimensions(); | ||
|
||
if (dims[0] != 610 && dims[1] != 406) | ||
{ | ||
std::cerr << "Incorrect EXR image size." << dims[0] << ":" << dims[1] << std::endl; | ||
return EXIT_FAILURE; | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,11 +8,60 @@ | |
#include "vtksys/FStream.hxx" | ||
|
||
#include <ImfArray.h> | ||
#include <ImfIO.h> | ||
#include <ImfRgbaFile.h> | ||
|
||
#include <cstring> | ||
#include <sstream> | ||
#include <thread> | ||
|
||
/** | ||
* 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)) | ||
{ | ||
} | ||
|
||
bool read(char c[], int n) override | ||
{ | ||
if (pos + n <= bufflen) | ||
{ | ||
memcpy(c, buffer + pos, n); | ||
pos += n; | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* 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 | ||
{ | ||
return pos; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why isn't this line covered? Do we need to override this function if it's not called? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from this page There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure to follow that answer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if that method is not used you can just remove it ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is a pure virtual function in the base class so i believe it needs an implementation. I can try removing it and see what happens. In the documentation i posted it says it needs an implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok lets try that. Maybe its needed in some case, but not in our case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it does not build without that function being implemented error: cannot declare variable ‘memoryStream’ to be of abstract type ‘MemStream’ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, lets keep it in for now. |
||
} | ||
|
||
/** | ||
* sets the current reading position to pos bytes from the beginning of the "file" | ||
*/ | ||
void seekg(uint64_t new_pos) override | ||
{ | ||
pos = new_pos; | ||
} | ||
|
||
private: | ||
const char* buffer; | ||
size_t bufflen; | ||
uint64_t pos{ 0 }; | ||
}; | ||
|
||
vtkStandardNewMacro(vtkF3DEXRReader); | ||
|
||
//------------------------------------------------------------------------------ | ||
|
@@ -36,15 +85,14 @@ | |
|
||
// Setup filename to read the header | ||
this->ComputeInternalFileName(this->DataExtent[4]); | ||
if (this->InternalFileName == nullptr || this->InternalFileName[0] == '\0') | ||
if ((this->InternalFileName == nullptr || this->InternalFileName[0] == '\0') && | ||
!this->MemoryBuffer) | ||
{ | ||
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; | ||
|
@@ -56,6 +104,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); | ||
} | ||
else | ||
{ | ||
Imf::RgbaInputFile file(this->InternalFileName); | ||
execute(file); | ||
} | ||
} | ||
catch (const std::exception& e) | ||
{ | ||
|
@@ -112,12 +175,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()); | ||
|
@@ -134,6 +193,27 @@ | |
dataPtr += 3; | ||
} | ||
} | ||
}; | ||
|
||
try | ||
{ | ||
Imf::setGlobalThreadCount(std::thread::hardware_concurrency()); | ||
|
||
if (this->MemoryBuffer) | ||
{ | ||
MemStream memoryStream("EXRmemoryStream", this->MemoryBuffer, this->MemoryBufferLength); | ||
Imf::RgbaInputFile file = Imf::RgbaInputFile(memoryStream); | ||
execute(file); | ||
} | ||
else | ||
{ | ||
if (!(this->InternalFileName)) | ||
{ | ||
throw std::invalid_argument("Not filename in EXR Reader when no Memory Buffer is set."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this happen ? Do you really need to throw here ? you could just error out ? |
||
} | ||
Imf::RgbaInputFile file(this->InternalFileName); | ||
execute(file); | ||
} | ||
} | ||
catch (const std::exception& e) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please also add `small.usdz: Copyright USD contributors: CC-BY 4.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with the links please