-
-
Notifications
You must be signed in to change notification settings - Fork 140
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
DecodePixelData incorrectly y flips the image when loading "Decreasing Y" files #213
Comments
Thank you for the detailed report. Let me give some time to investigate the issue(and the spec of EXR lineOrder) |
I think that
because regardless of the order of the scanlines in the file, the scanline for For the case where If |
Firstly, Dumping line_no info at here: Line 5318 in 756f7d3 for Blobbies.exr gives the following result.
NOTE: ZIP compression(used on Blobbies.exr) uses 16 scanlines(num_lines) per block. So, i'th block(scanline) corresponds to i'th block(scanline) position(no change to the ordering of scanline) but offset(memory address) is descending order for decreasing Y. Also, scanline data itself in the memory seems not flipped when |
@MarkCallow Could you please prepare synthetic EXR image with decreasing Y, with compression none(num_lines = 1) and ZIP(num_lines=16) using OpenEXR lib? e.g. height 256 image, whose y'th scanline value has 'y'. |
What is
|
You should read the comment here: Line 5338 in 756f7d3
Blobbies.exr has negative value in
? testexrorder.zip has C++ code with OpenEXR lib. |
Thanks. I'll have to study the data window. I'm new to EXR.
I did not write that. It was written by @peterhillman and provided by him in AcademySoftwareFoundation/openexr#1946 (comment) to help explain decreasing scanline order to me. |
You should not post someone's code. There is no meaningful info about lineOrder attribute in the OpenEXR spec, so you need to check the source code of OpenEXR. After some code investigation, lineOrder handling when reading the image changed from openexr 2.0(TinyEXR is based on) and openexr 3.0. For example, there is no lineOrder consideration anymore in recent ImfScanLineInputFile.cpp Whereas lineOrder is considered in openexr 2.0 So flipping may be an expected behavior in openexr 2.0. You need to prepare reproducible code with openexr 2.0 and openexr 3.0, and check if how it behaves. |
As far as I can tell, all versions of the OpenEXR C++ library load the image the same way up. I've tested back to OpenEXR-1.6.1, and all load the Blobbies.exr image correctly, consistent with Blobbies.jpg I agree that the OpenEXR documentation isn't very clear what lineOrder does. It does say (here) that the scanline block starts with the y coordinate of the top scanline within a block, which suggests the topmost scanline is always the one with the smallest y coordinate value in its block header. It also says the scanlines are stored from top to bottom within each chunk - it doesn't say that's dependent on line order either. This is consistent with how the library behaves. The logic you see in OpenEXR-2.0 and earlier was an optimization, and doesn't change the layout of the data as read. Relevant comments are in the code here and here. When calling The latest OpenEXR library (3.3 onwards) uses the C OpenEXRCore library to do much of the file reader, which explains why much of the code has disappeared from the C++ library classes which read files. That hasn't changed behavior of the lineOrder, though. The Core library uses To be clear, with all versions of the OpenEXR C++ library, calling readPixels(dataWindow.min.y) will read the topmost scanline in the file into the beginning of the provided data buffer, regardless of lineOrder. It seems tinyEXR puts that scanline at the end of the provided buffer if the lineOrder is set to DECREASING_Y. |
Thank you for your comment @peterhillman. I apologize if you were bothered by my including your It seems to me that the following are true of the EXR format:
I doubt these fundamental things have changed with different versions of the format. Therefore I think that whether a library
is entirely up to the library and independent of the format. I do not know the reasons for supporting decreasing Y in EXR but behavior no. 1 seems to make it pointless. If it is to be useful to some programs it must be visible to them so the library should do no. 2 or no. 3. Whatever it does MUST be documented. Perhaps documentation is all it takes to resolve this issue. I have no particular preference. |
Thanks @MarkCallow. I have no concerns about sharing the code. I should have added a copyright line and license identifier to the code, but I had intended it to be shared as a minimal example. I would suggest the third option could be the best: have a parameter which specifies which order the image is decoded into, regardless of the arrangement of the file. DECREASING_Y lineOrder files are somewhat unusual, so It would be better if the library handled them internally, rather than relying on calling code to handle them correctly, and for authors to find suitable test cases to verify their code. In other words, code using a library should get the same data buffer regardless of the lineOrder of the source file. For backwards compatibility tinyexr might continue to default to matching decoded data order to file order, but provide an option to fix the decoded data order, and strongly encourage setting it to the required order. That said, I suspect many people using the library assume the first bytes are always the top of the image, so changing the default behavior is likely to be a helpful change. For reading images into OpenGL textures, where y=0 is at the bottom, software could ask for the image to be flipped by tinyexr for all images, as it currently does for DECREASING_Y images. The statement of the file structure is a good summary. For accuracy, it is worth clarifying that the topmost scanline is dataWindow.min.y which is often y=0 but is not always. The DisplayWindow examples in openexr-images have cases where this isn't true. Also scanlines are usually compressed in groups. The group size depends on the compression scheme. Each group is labelled with its smallest y coordinate, and the offset table contains one entry per group. DECREASING_Y lineOrder is a feature provided for writing files. It is possible to create an OpenEXR image that is very much larger than the amount of memory available to a process by generating a few scanlines at once in a memory buffer, writing them to the file, then reusing the same memory to generate the next scanlines. Software doing that must write the scanlines to file in the order specified by lineOrder. So, if it needs to start at the bottom of the image (largest y coordinate), and work upwards, it must use DECREASING_Y lineOrder, so the first scanlines it generates can be written to the file first. |
Describe the issue
I think the title is a clear and concise description.
To Reproduce
Steps to reproduce the behavior:
decreasing.exr
, in testexrorder.zip attached below.LoadEXRImageFromMemory
to load the file.testexrorder.zip contains increasing and decreasing versions of the same simple 3 line image. See AcademySoftwareFoundation/openexr#1946 (comment) for a detailed description of the test case.
The same issue arises using the only decreasing Y file I found in the Academy's EXR test files: https://raw.githubusercontent.com/AcademySoftwareFoundation/openexr-images/main/ScanLines/Blobbies.jpg.
Expected behavior
I got this result:
I expected this
Ignore that it is red (the sole channel in the file is labelled "R" which my software follows) and the lighter area (this is from a 3D scene with illumination).
The images in "decreasing.exr" and "increasing.exr" are identical so the result should be identical.
** My Analysis **
The source
data_ptr
passed toDecodePixelData
is acquired fromoffsets[y_idx]
wherey_idx
essentially becomes theline_no
parameter also passed toDecodePixelData
. Sodata_ptr
is pointing at the correct source for, e.g. line 0 so it just needs to be copied to the first scanline in the output image.But in
DecodePixelData
we see lines liketinyexr/tinyexr.h
Lines 4100 to 4105 in 5fcb4dc
The above is taken from the uncompressed case as being the simplest example.
We can see that for decreasing line order it sets the output pointer to the last scanline of the output and proceeds to write scanline 0 there.
I can workaround this by setting
line_order = 0
in the header I pass toLoadEXRImageFromMemory
. But I am worried this might not work for, lets say, more complex cases. In both the examples I've referencedDecodePixelData
is called once for each scanline withnum_lines == 1
. I do not know enough about EXR or TinyEXR to judge what cases, if any, would be broken by simply removing theif (line_order == 0)
clauses and always performing the line_order == 0 case.num_lines > 1
looks iffy to me.Environment
The text was updated successfully, but these errors were encountered: