Jump to content
Alexander Halser

Loading a JPEG into FMX.TBitmap honoring EXIF orientation

Recommended Posts

This is a blank FMX form in Delphi 11 with a TImage control, that loads a JPEG. The JPEG picture was created with a Samsung smart phone in portrait mode. Hence, the picture has a width of 2268 and a height of 4032 pixels. The JPEG's EXIF header states that orientation is portrait.

 

That's obvious for everyone who looks at the picture, except for Delphi Firemonkey. TBitmap.LoadfromFile() ignores the EXIF orientation altogether and loads the JPEG with its physical dimensions (which are width 4032 and height 2268 pixels). It doesn't rotate the picture after loading.

 

Has anyone solved this nasty problem for FMX?

Untitled.png

Share this post


Link to post

I wonder if anyone is interested in a solution... 😉

 

Just in case you are, here is what I did.

 

  • Neither FMX nor VCL will honor the orientation information in the EXIF header inside the JPEG.
  • For FMX: neither on Windows nor on macOS. And probably not on iOS, either. For Android and Linus, you need to test for yourself, maybe they do.
  • The only solution is to read the EXIF header, extract the Orientation tag and apply the necessary transformations to the image after loading.
  • There are several components for Delphi to read EXIF headers, some do work, some don't. The best known unit is CCR-Exif (https://github.com/Wolfcast/ccr-exif), which does everything and works quite well. It can read and write EXIF tags.
  • I've created my own, because CCR-Exif seems like overkill (after all, I just want to know 1 single byte in the JPEG)


If you want to display JPEG images correctly in your FMX application, I have published my little unit on SourceForge, It's as small and fast as possible with really minimal overhead.

 

The first function JPEGRotationFromStream() will work for VCL as well! So you can adapt it and use it for your VCL app, too.

But FMX has this nice little class called TBitmapSurface, which easily does the Rotate, Mirror and Flip transformations that are required to display the JPEG correctly. So, for FMX this unit goes the full length and delivers a TBitmap that's just right. The unit might be useful for VCL as well, but you have to go an extra mile to apply the transformations.

 

SourceForge Download:

https://sourceforge.net/projects/delphi-fmx-jpeg-loader-exif/

 

 

delphi-fmx-tbitmap-load-jpeg.png

  • Like 3

Share this post


Link to post
22 hours ago, Alexander Halser said:

That's obvious for everyone who looks at the picture, except for Delphi Firemonkey. TBitmap.LoadfromFile() ignores the EXIF orientation altogether and loads the JPEG with its physical dimensions (which are width 4032 and height 2268 pixels). It doesn't rotate the picture after loading.

FWIW, TBitmap/TJPEGImage are low-level image containers. It's not their job to rotate or mirror the image because they don't know what you want to do with the image after load.

 

So, if anything, the problem is that the classes don't surface the EXIF information so you can apply the transformation after load if you want to.

  • Like 1

Share this post


Link to post
Just now, Anders Melander said:

problem is that the classes don't surface the EXIF information

Agreed. But this EXIF information is crucial (at least the orientation), from a practical point of view.

Share this post


Link to post

Definitely. I'm not denying that it's a problem. I'm just saying that the problem isn't that it doesn't rotate automatically (because that would also be a problem). The problem is that it doesn't give us any way of knowing that the image needs to be rotated be display.

You should probably report it as a bug against FMX.

  • Like 1

Share this post


Link to post
3 minutes ago, Anders Melander said:

The problem is that it doesn't give us any way of knowing that the image needs to be rotated be display. 

Yes, that's the core issue. When loading an image, we must know - or be able to know - if it requires extra handling. Then we can make an informed decision. For myself, the issue is solved with the Jpeg-load-helper unit. Now I have to implement that in VCL as well... 🙂

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×