Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
51 changes: 42 additions & 9 deletions src/wrappers/python/PyOpenEXR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,29 @@ PyFile::PyFile(const py::dict& header, const py::dict& channels)
// e.g. "left.R", "left.G", etc, the channel key is the prefix.
//

PyFile::PyFile(const std::string& filename, bool separate_channels, bool header_only)
PyFile::PyFile(const std::string& filename, bool separate_channels, bool header_only, const py::list& part_indices)
: filename(filename),
_header_only(header_only),
_inputFile(std::make_unique<MultiPartInputFile>(filename.c_str()))
{

for (int part_index = 0; part_index < _inputFile->parts(); part_index++)
std::vector<int> indices_to_process;
if (part_indices.empty()) {
// If no specific parts requested, process all parts
for (int i = 0; i < _inputFile->parts(); i++) {
indices_to_process.push_back(i);
}
} else {
// Otherwise, process only the requested parts
for (auto idx : part_indices) {
int part_idx = py::cast<int>(idx);
if (part_idx >= 0 && part_idx < _inputFile->parts()) {
indices_to_process.push_back(part_idx);
}
}
}

for (int part_index : indices_to_process)
{
const Header& header = _inputFile->header(part_index);

Expand Down Expand Up @@ -209,17 +225,29 @@ PyFile::PyFile(const std::string& filename, bool separate_channels, bool header_
//

auto type = header.type();
if (type == SCANLINEIMAGE || type == TILEDIMAGE)
try
{
P.readPixels(*_inputFile, header.channels(), shape, rgbaChannels, dw, separate_channels);
if (type == SCANLINEIMAGE || type == TILEDIMAGE)
{
P.readPixels(*_inputFile, header.channels(), shape, rgbaChannels, dw, separate_channels);
}
else if (type == DEEPSCANLINE || type == DEEPTILE)
{
P.readDeepPixels(*_inputFile, type, header.channels(), shape, rgbaChannels, dw, separate_channels);
}
parts.append(py::cast<PyPart>(PyPart(P)));
}
else if (type == DEEPSCANLINE || type == DEEPTILE)
catch (const std::exception& e)
{
P.readDeepPixels(*_inputFile, type, header.channels(), shape, rgbaChannels, dw, separate_channels);
// Log the error and skip appending this part
py::print("Warning: Exception raised reading pixel data for part", part_index, "-", e.what());
}
}

parts.append(py::cast<PyPart>(PyPart(P)));
else
{
// If only reading the header, always append this part
parts.append(py::cast<PyPart>(PyPart(P)));
}
} // for parts
}

Expand Down Expand Up @@ -2745,10 +2773,11 @@ PYBIND11_MODULE(OpenEXR, m)
>>> f.write("out.exr")
)pbdoc")
.def(py::init<>())
.def(py::init<std::string,bool,bool>(),
.def(py::init<std::string,bool,bool,py::list>(),
py::arg("filename"),
py::arg("separate_channels")=false,
py::arg("header_only")=false,
py::arg("part_indices")=py::list(),
R"pbdoc(
Initialize a File by reading the image from the given filename.

Expand All @@ -2761,10 +2790,14 @@ PYBIND11_MODULE(OpenEXR, m)
if False (default), read pixel data into a single "RGB" or "RGBA" numpy array of dimension (height,width,3) or (height,width,4);
header_only : bool
If True, read only the header metadata, not the image pixel data.
part_indices : list
List of part indices to read. If empty, all parts are read.

Example
-------
>>> f = OpenEXR.File("image.exr", separate_channels=False, header_only=False)
>>> # Read only parts 0 and 2
>>> f = OpenEXR.File("multipart.exr", part_indices=[0, 2])
)pbdoc")
.def(py::init<py::dict,py::dict>(),
py::arg("header"),
Expand Down
2 changes: 1 addition & 1 deletion src/wrappers/python/PyOpenEXR.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class PyFile
{
public:
PyFile();
PyFile(const std::string& filename, bool separate_channels = false, bool header_only = false);
PyFile(const std::string& filename, bool separate_channels = false, bool header_only = false, const py::list& part_indices = py::list());
PyFile(const py::dict& header, const py::dict& channels);
PyFile(const py::list& parts);

Expand Down
Loading