Search code examples
c#imageexif

How to fix EXIF orientation data in JPG files


I have a digital photo frame that showcases all my best family shots over the past 20 years. It's always worked fine for both portrait and landscape oriented photos.

Now I got a new cellphone (Xiaomi Mi A1) over a year ago, with a fabulous camera function, but unfortunately all the photos take on that camera are displaying rotated 90 degrees on the photo frame. The old portrait photos still show up fine, and my portrait photos from the new camera display fine on my computer, Google Photos, etc. But when I load them into the photo frame, they are rotated 90 degrees.

I asked on SuperUser, and got an answer that the orientation info is in the EXIF data, which apparently is in a format that every other image reader understands, but my photo frame doesn't, and I need to modify all my portrait-oriented images in an image editor so that the frame recognizes the EXIF data.

Being a programmer, obviously I'm not going to do this manually. But I have no idea how to view or edit EXIF data of a JPG.

Anyone have any code snippets handy for changing the orientation of a JPG? C# preferred.


Solution

  • As you say, there is orientation data in Exif. It defines how the raw pixel data should be transformed before being displayed (rotation, but also potentially flipping on either axis).

    For a JPEG image with Exif, the 'easy' way to rotate the image is just to update the Exif info. Of course this requires the viewer to honour that rotation information.

    The more expensive way (and potentially lossy) is to physically rotate the image data. I suspect that this is what you need to do to satisfy your photo frame.

    In .NET you can do this with System.Windows.Drawing, for example. The Image.RotateFlip method would be a good place to start.

    To extract the orientation data from your image, may I humbly suggest using my MetadataExtractor library?

    var orientation = ImageMetadataReader.ReadMetadata(myImagePath)
        .OfType<ExifIfd0Directory>()
        .FirstOrDefault()
        ?.GetObject(ExifIfd0Directory.TagOrientation);
    

    That'll give you an int?, the values of which are:

    1. Top, left side (Horizontal / normal)
    2. Top, right side (Mirror horizontal)
    3. Bottom, right side (Rotate 180)
    4. Bottom, left side (Mirror vertical)
    5. Left side, top (Mirror horizontal and rotate 270 CW)
    6. Right side, top (Rotate 90 CW)
    7. Right side, bottom (Mirror horizontal and rotate 90 CW)
    8. Left side, bottom (Rotate 270 CW)

    An aside here, mostly because it's interesting: JPEG images are encoded as a grid of 16x16 pixel 'blocks'. If your image is not exactly a multiple of 16 pixels in both directions, then rotation can potentially shift the alignment of this grid which will result in decoding and re-encoding of the images, which will lose information. If the original JPEG has low compression then you probably won't be able to perceive this loss, so it may be academic to point it out, but it will still be there.