Skip to content
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

blobbies.jpg is upside down, differs from blobbies.exr #1946

Open
MarkCallow opened this issue Dec 29, 2024 · 12 comments
Open

blobbies.jpg is upside down, differs from blobbies.exr #1946

MarkCallow opened this issue Dec 29, 2024 · 12 comments

Comments

@MarkCallow
Copy link

The jpg for the test image blobbies.exr, https://raw.githubusercontent.com/AcademySoftwareFoundation/openexr-images/main/ScanLines/Blobbies.jpg, is upside down. blobbies.exr has `lineOrder: 1 (decreasing Y). Whatever was used to make the JPEG failed to pay attention and did not flip the image to JPEG top-left origin.

I was specifically seeking a file with decreasing Y to use to test handling in my loader, which uses TinyEXR under the covers, and application. At first I was coming up with all sorts of wild theories why the results on my screen did not match the JPEG on your website including that macOS Preview and Finder were ignoring lineOrder. Nothing made sense so I created my own This Way Up image

up_RGBA8_128x128_sRGB

I used Image Magick to create an EXR file from this .png with the image y-flipped. It still had lineOrder: 0 because IM provides no way to set it. In Finder and Preview I saw the image upside down as expected. I then used a hex editor to change lineOrder to 1. After this Finder and Preview show the image the correct way up. Therefore they are also showing blobbies.exr the correct way up and it is your JPEG image that is wrong. Here is a zip file of the .exr. It's not very good HDR but meets the purpose for which it was created.

up_decreasing_y.exr.zip

@peterhillman
Copy link
Contributor

I think there's a misunderstanding here: OpenEXR always has (0,0) in the top left corner, so the scanline with the smallest y coordinate is always the topmost scanline. With lineOrder set to decreasing Y, the scanlines are written to disk backwards: the first scanline in the file is the one that has the largest y coordinate (i.e. dataWindow.max.y)

"decreasing Y" lineOrder is a convenience for software which processes the bottom of the image first and works upwards. However, (0,0) is still the top left corner in this case, because lineOrder controls the arrangement of data on the disk, not the orientation of the image or its coordinate system.

Software reading OpenEXR images through the library can safely ignore the lineOrderr. It should not flip the image on reading 'descending Y' images.

Your crafted file is actually an invalid EXR, because the lineOrder indicates that the scanlines will appear in reverse order, but scanline 0 is still first, instead of last.

@MarkCallow
Copy link
Author

MarkCallow commented Dec 30, 2024

I think there's a misunderstanding here: OpenEXR always has (0,0) in the top left corner, so the scanline with the smallest y coordinate is always the topmost scanline. With lineOrder set to decreasing Y, the scanlines are written to disk backwards: the first scanline in the file is the one that has the largest y coordinate (i.e. dataWindow.max.y)

"decreasing Y" lineOrder is a convenience for software which processes the bottom of the image first and works upwards. However, (0,0) is still the top left corner in this case, because lineOrder controls the arrangement of data on the disk, not the orientation of the image or its coordinate system.

Whether you call the top-left corner 0,0 is an arbitrary choice. I think the important thing is that for increasing Y, the first scanline in the file is the scanline at the logical top of the image (as viewed by a human) while for decreasing Y the last scanline in the file is the scanline at the logical top of the image. In both cases EXR calls this scanline Y=0. Absolutely fine.

Software reading OpenEXR images through the library can safely ignore the lineOrderr. It should not flip the image on reading 'descending Y' images.

"Flip the image" was sloppy usage. Sorry. I should have said flip the scanline order in my original post. I am not sure of the context for "flip the image" in your sentence above but macOS Preview and Finder most certainly flip the scanline order which results in the logical top of the image appearing at the top instead of the bottom which happened when lineOrder was still set to increasing.

Your crafted file is actually an invalid EXR, because the lineOrder indicates that the scanlines will appear in reverse order, but scanline 0 is still first, instead of last.

I don't understand. What do you consider to be scanline 0 in the file? The file I posted has the logical top if the image in the last scanline in the file. I have another file with it in the first scanline in the file with lineOrder set to increasing Y. In Finder and Preview both .exr files are displayed correctly with the arrows pointing up.

@peterhillman
Copy link
Contributor

Well, now I'm less sure myself...

I've checked Preview on Sequoia 15.1.1 and I think it does display 'decreasing Y' images upside down. I think that Preview is buggy, but the JPEGs on the site and OpenImageIO are correct. It certainly seems there needs to be a better example of 'descending y' images to clarify things!

By "Scanline 0" I mean "the scanline that is labelled as having a y coordinate of 0 in the file". That's always the topmost scanline in OpenEXR, appearing above "scanline 1" when displayed. When you make an API call to readPixels(0) you get the topmost scanline. Depending on lineOrder, that's either at the beginning or the end of the file, but shouldn't need to ask what the lineOrder is to display the image.

Here are two EXR images with the same content written with INCREASING_Y and DECREASING_Y, the same files converted to JPEG by OpenImageIO's oiiotool, and the C++ that wrote them:
testexrorder.zip

Both images should be rendered as three pixels, which from top to bottom should be black, gray and white. Preview displays descending.exr upside down from increasing.exr, which is incorrect. Flipping the lineOrder byte with a hex editor, without modifying anything else, does seem to flip the image in Preview, but that's a bug. It seems to be interpreting lineOrder rather like the TIFF/EXIF Orientation attribute, but that's not what it's for.

...

Getting into the weeds, examining increasing.exr and decreasing.exr in a hex editor should help to clarify what 'descending Y' means for how files are written to disk. OpenEXR files have the following structure:

[Header][Scanline Offset Table][Scanlines]

In both cases here, the header is 277 bytes and the scanline offset table has three 8 byte entries since there are three scanlines. Scanlines themselves have

[4 byte y coordinate of scanline][4 byte data size][data]

The offset table stores the offset in the file of each scanline when indexed by its y coordinate. For increasing.exr, the offset table stores 301 311 321 and the y coordinates stored in the scanlines themselves appear in the order 0 1 2. The last scanline in the file is marked as y=2, the white pixel at the bottom, which has value 1.0 in half float (0x003C)

For decreasing.exr the offset table stores 321 311 301 (so scanline y=0 is at byte 321 and scanline y=2 is at byte 301), and the y coordinates appear in the order 2 1 0. The last scanline in the file is y=0, the black pixel at the top.

In both images, scanline 0 is the topmost scanline with the black pixel, and scanline 2 the bottommost with the white one, but they have been written into the file in a different order.

Your up_decreasing_y image still has the scanline with y=0 appearing first, with the scanlines appearing in increasing order of y coordinate. So, as far as OpenEXR is concerned, the logical top of your image is still the first scanline in the file, not the last.

(for pedantry, the above explanation assumes that the image dataWindow.min.y is 0, which isn't always required. The topmost scanline in the file - and the first entry in the offset table - is actually dataWindow.min.y and the bottommost dataWindow.max.y)

@MarkCallow
Copy link
Author

MarkCallow commented Dec 31, 2024

Hmm? https://viewer.openhdr.org shows the same result as the .jpg file. On the other hand TinyEXR flips the scanlines for decreasing Y giving a result that is the same as Preview but upside down from https://viewer.openhdr.org and the .jpg. Only if I change line_order to 0 (increasing) in the header passed to LoadEXRImageFromMemory do I get the same result as the .jpg. line_order 0 prevents the scanline flipping. Clearly I need more study to understand what is really going on. Could TinyEXR be buggy? As for Preview, it seems it is paying attention to lineOrder, as the result changed when I flipped that bit in my file. It seems it is misinterpreting too.

Is there a tool that can be used to view the scanline offset table and the y coordinates of each scanline? I understand now why you said my file is invalid. I did not update the scanline offset table or scanline y coordinates only lineOrder. I'd better look at oiiotool to convert my .png input to .exr.

@peterhillman
Copy link
Contributor

I think TinyEXR is flipping the data in the output buffer based on the line order e.g. here. I didn't delve too deeply but I think line_no is the y coordinate of the scanline, as read from the header of the scanline being decoded. That doesn't seem correct to me. The OpenEXR library always puts the topmost scanline (y=0) first in the specified FrameBuffer, but TinyEXR doesn't.

Good idea about the diagnostic tool: perhaps exrinfo could be extended with options to dump the offset tables and perhaps the header of each scanline/tile

@MarkCallow
Copy link
Author

MarkCallow commented Dec 31, 2024

I tested TinyEXR with your testextorder files. The results are different for each file. The black pixel appears at the top for increasing.exr and at the bottom for decreasing.exr. Is this repo the right place to file an issue?

The test files have only 1 component. The included jpegs show it as greyscale as do Finder and Preview. However https://viewer.openhdr.org shows is as red, as does my own program which uses Vulkan for rendering. Both obviously have the single component in the R component of the textures they make. Does the EXR spec say 1-component files must be treated as greyscale? If so, both pieces of software need fixing.

Happy New Year to you @peterhillman and thanks for your help.

@meshula
Copy link
Contributor

meshula commented Dec 31, 2024

Here's the official repo to report issues with tinyexr: https://github.com/syoyo/tinyexr
If we are confident Apple's Preview is incorrectly flipping the image, a bug should be entered with Apple's bug reporter. If you do so, please report the number here so we can follow up.

@lgritz
Copy link
Contributor

lgritz commented Dec 31, 2024

Does the EXR spec say 1-component files must be treated as greyscale?

The EXR spec says channels have names. So if it's "R", maybe it should be displayed as Red, but if it's "Y" or "Luma" or whatever, then it should be grayscale? (Though my personal opinion is always grayscale; it just doesn't make sense to have a file that has only one of R, G, or B -- to me, that very likely indicates a mislabeled channel or a creator who doesn't know what they are doing.)

@peterhillman
Copy link
Contributor

I agree the spec technically says that image should come out red. There's a bunch of code in the API so that you can ask for a G or B buffer, and if the file doesn't contain that channel then it'll fill your buffer with a default value. So, images with only a single RGB component are officially supported. If you know a channel is completely empty it might be a considerable space saving to drop it from the image entirely. However, it's such a weird situation that it's probably not worth the effort to get everybody to change their code.

I wonder if tools are more consistent when an image has two RGB channels and is only missing one?

@MarkCallow
Copy link
Author

I've opened syoyo/tinyexr#213 about the incorrect y flip.

Here is a screen shot from Finder of the testexrorder directory.
Screenshot 2025-01-02 at 17 46 43

I don't know what's going on with decreasing.exr. Here are images from Preview which does show all 3 lines:

Screenshot 2025-01-02 at 17 48 43 Screenshot 2025-01-02 at 17 48 56

It seems clear macOS has problems so I'll file an issue with Apple too.

@peterhillman is there any tool I can use to write an EXR file with decreasing Y or do I have to resort to writing a program like you did for testexrorder?

@MarkCallow
Copy link
Author

If we are confident Apple's Preview is incorrectly flipping the image, a bug should be entered with Apple's bug reporter. If you do so, please report the number here so we can follow up.

I filed an issue via Apple's Feedback Assistant. The number is FB16220290. I have no idea if anybody outside Apple or myself can see this.

@MarkCallow
Copy link
Author

Now that I've reported the discussed issues in the appropriate places I'm closing this as the .jpeg is clearly correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants