Two weeks ago I received an interesting support ticket from a
user of our ImageBox control, stating that when being used
.png files, the control was absolutely file but when used
.jpg files that had been rotated using Windows Explorer
shell context menus, they were displayed in the original
As soon as I read the ticket I had a hunch what was going to be the ultimate cause, and was able to quickly reproduce the problem and then confirm my hunch.
Introducing exchangeable image file format
JEPG images support extension attributes via the Exchangeable image file format (Exif). These attributes can be used to provide additional information about an image, such as how and where it was captured. It can also store information such as the software used to manipulate the image, artist and copyright information, or camera model details. In other words, it's similar to how you can add tags to an MP3 file with album information, although usually this doesn't cause your MP3 file to play backwards!
The Exif specification is available from the CIPA website, although at 191 pages long it is a hefty read.
Introducing the orientation attribute
I mentioned that MP3 tags don't cause your MP3 files to play backwards (at least I'm not aware of any that do!), but Exif supports an orientation attribute that means the source image has one orientation, but should be displayed in another in order to appear correctly.
The tag supports one of the following 8 values
|EXIF Orientation Value||Row #0 is:||Column #0 is:|
The starred values also flip the image in addition to rotating it.
Source: ImpulseAdventure - JPEG / Exif Orientation and Rotation
Enter Windows Explorer
Windows Explorer has knowledge of the Exif orientation tag, and automatically rotates thumbnail previews so they appear correct - very helpful!
However, if you context click an image and make use of the Rotate Left and Rotate Right commands, Explorer doesn't truly rotate the images. Instead, for JEPG images, an appropriate orientation attribute is added (plus a large block of XML, it wouldn't be Microsoft if they weren't adding extra unwanted data in files). This is quite clever in a way, as it means it doesn't touch the original image data at all, but does mean that any application that doesn't understand Exif is going to display the image wrong.
Also somewhat annoyingly, when you view the properties of the image, the Details tab includes lots of information gleaned from Exif - but neglects to mention that a custom orientation is in use.
When it comes to loading images in .NET, I usually use
Image.FromStream if I'm just loading
common formats. Unfortunately, these return the images "as-is",
without doing any post processing. I said unfortunately, but
actually this is probably a good thing - most likely you don't
want .NET manipulating images for you.
Fixing the problem
Image class does provide access to Exif properties, albeit
in a very obsure way.
Image.PropertyIdList returns an
array of defined extension values, and
PropertyItem instance describing an existing
property. You can then use the
Value property to get the
attribute value, although this may require further conversion to
use (e.g. convert raw bytes into a string).
GetPropertyItemwill throw an
ArgumentExceptionif you request a property that doesn't exist. You should use
PropertyIdListto check that the property exists first.
The following extension method (body code from this Stack
Overflow answer) will take a source
Image, check to see if
the orientation attribute is present and if it is rotate/flip
the image as appropriate and then remove the attribute.
If your application deals with user submitted images, having something like this in your arsenal may be useful; I know I have several applications that now need this "fix".
The linked source code download includes a demonstration program that features each of 8 supported orientation values and shows how they are displayed both before and after processing the orientation attribute.
At this time I'm still mulling over if this is something I should be handling within ImageBox, or if it is the responsibility of the program using the control. Given ImageBox typical use cases, I'm leaning towards the idea of adding a new option to automatically handle this but am currently undecided.
- Tower of London photograph used for sample images - Vera Kratochvil
- Information on Exif orientation - ImpulseAdventure
- Code for processing Exif orientation tags in C# - ReenignE
- 2019-03-09 - First published
- 2020-11-22 - Updated formatting
Like what you're reading? Perhaps you like to buy us a coffee?