diff --git a/vtkext/private/module/vtkF3DEXRReader.cxx b/vtkext/private/module/vtkF3DEXRReader.cxx
index 4eb4f28dff..efda8725e1 100644
--- a/vtkext/private/module/vtkF3DEXRReader.cxx
+++ b/vtkext/private/module/vtkF3DEXRReader.cxx
@@ -15,6 +15,53 @@
 
 vtkStandardNewMacro(vtkF3DEXRReader);
 
+  /**
+   * 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)
+    {
+    }
+
+    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
+    {
+      return pos;
+    }
+
+    /**
+     * sets the current reading position to pos bytes from the beginning of the "file"
+     */
+    void seekg(uint64_t new_pos) override
+    {
+      pos = new_pos;
+    }
+
+    /**
+     * clears any error flags (we dont have to worry about this)
+     */
+    void clear() override
+    {
+    }
+
+  private:
+    const char* buffer;
+    size_t bufflen;
+    uint64_t pos;
+};
+
+
 //------------------------------------------------------------------------------
 vtkF3DEXRReader::vtkF3DEXRReader() = default;
 
@@ -38,31 +85,48 @@ void vtkF3DEXRReader::ExecuteInformation()
   this->ComputeInternalFileName(this->DataExtent[4]);
   if (this->InternalFileName == nullptr || this->InternalFileName[0] == '\0')
   {
-    return;
+    if (!this->GetMemoryBuffer()){
+      return;
+    }
   }
 
-  try
-  {
-    Imf::RgbaInputFile file(this->InternalFileName);
-
-    Imath::Box2i dw = file.dataWindow();
-    this->DataExtent[0] = dw.min.x;
-    this->DataExtent[1] = dw.max.x;
-    this->DataExtent[2] = dw.min.y;
-    this->DataExtent[3] = dw.max.y;
-
-    Imf::RgbaChannels channels = file.channels();
-    if (channels != Imf::RgbaChannels::WRITE_RGBA && channels != Imf::RgbaChannels::WRITE_RGB)
+  if (this->GetMemoryBuffer()){
+    try
+    {
+      MemStream memoryStream("EXRmemoryStream", this->MemoryBuffer, this->MemoryBufferLength);
+      Imf::RgbaInputFile file = Imf::RgbaInputFile(memoryStream);
+      execute(file);
+    }
+    catch (const std::exception& e)
     {
-      throw std::runtime_error("only RGB and RGBA channels are supported");
+      vtkErrorMacro("Error reading EXR file (from memory): " << e.what());
+      return;
     }
   }
-  catch (const std::exception& e)
-  {
-    vtkErrorMacro("Error reading EXR file: " << e.what());
-    return;
+  else{
+    try
+    {
+      Imf::RgbaInputFile file(this->InternalFileName);
+    
+      Imath::Box2i dw = file.dataWindow();
+      this->DataExtent[0] = dw.min.x;
+      this->DataExtent[1] = dw.max.x;
+      this->DataExtent[2] = dw.min.y;
+      this->DataExtent[3] = dw.max.y;
+    
+      Imf::RgbaChannels channels = file.channels();
+      if (channels != Imf::RgbaChannels::WRITE_RGBA && channels != Imf::RgbaChannels::WRITE_RGB)
+      {
+        throw std::runtime_error("only RGB and RGBA channels are supported");
+      }
+    }
+    catch (const std::exception& e)
+    {
+      vtkErrorMacro("Error reading EXR file: " << e.what());
+      return;
+    }
   }
-
+  
   this->SetNumberOfScalarComponents(3);
   this->SetDataScalarTypeToFloat();
 
@@ -112,6 +176,22 @@ void vtkF3DEXRReader::ExecuteDataWithInformation(vtkDataObject* output, vtkInfor
   scalars->SetName("Pixels");
   float* dataPtr = scalars->GetPointer(0);
 
+  if (this->GetMemoryBuffer()){
+    try
+    {
+      assert(this->InternalFileName);
+      Imf::setGlobalThreadCount(std::thread::hardware_concurrency());
+      MemStream memoryStream("EXRmemoryStream", this->MemoryBuffer, this->MemoryBufferLength);
+      Imf::RgbaInputFile file = Imf::RgbaInputFile(memoryStream);
+      execute(file);
+    }
+    catch (const std::exception& e)
+    {
+      vtkErrorMacro("Error reading EXR file (from memory): " << e.what());
+      return;
+    }
+  }
+  
   try
   {
     assert(this->InternalFileName);
@@ -142,6 +222,24 @@ void vtkF3DEXRReader::ExecuteDataWithInformation(vtkDataObject* output, vtkInfor
   }
 }
 
+//------------------------------------------------------------------------------
+void vtkF3DEXRReader::SetMemoryBuffer(const void* buff)
+{
+  if (this->MemoryBuffer != buff)
+  {
+    this->MemoryBuffer = buff;
+  }
+}
+
+//------------------------------------------------------------------------------
+void vtkF3DEXRReader::SetMemoryBufferLength(vtkIdType buflen)
+{
+  if (this->MemoryBufferLength != buflen)
+  {
+    this->MemoryBufferLength = buflen;
+  }
+}
+
 //------------------------------------------------------------------------------
 int vtkF3DEXRReader::GetWidth() const
 {
@@ -153,3 +251,5 @@ int vtkF3DEXRReader::GetHeight() const
 {
   return this->DataExtent[3] - this->DataExtent[2] + 1;
 }
+
+