Read an image file’s EXIF orientation data in C#

[EXIF]

The EXchangeable Image File (EXIF) standard defines all sorts of information that a camera can add to a jpg file. For example, the camera may record latitude, longitude, altitude, date and time, focal length, shutter speed, and resolution. This example shows how to get an image’s orientation information.

Note that not all cameras can set EXIF information and some that can may not unless you use the proper settings. The two pictures included with this example do contain EXIF orientation information so you can test the program.

The Image class (from which Bitmap inherits) provides three useful items for working with EXIF data: the PropertyIdList property, the GetPropertyItem method, and the SetPropertyItem method.

The PropertyIdList property returns an array of integers giving the IDs of the properties stored in the image. You can use Array.IndexOf to try to find the index of a particular property’s ID in this array. If the image doesn’t contain information for that property, then Array.IndexOf returns -1.

The GetPropertyItem method returns a PropertyItem object containing information about a property. You need to pass GetPropertyItem the ID of the item you want to retrieve.

The PropertyItem class has the properties Id (the property’s ID), Len (the length in bytes of the property’s value), Type (defines the type of data in the Value property), and Value (the value).

The SetPropertyItem method sets a property’s value. Unfortunately there is no constructor for the PropertyItem class so you cannot create one from scratch. You can, however, get a PropertyItem object from an image and then modify it.

The orientation property’s ID is 0x0112. The PropertyItem for the orientation property holds an array of bytes in its Value property, with the first byte giving the orientation. The following picture shows the meanings of the orientations demonstrated by the letter F.


[EXIF]

The example program defines a static ExifStuff class to hold EXIF methods. Here’s how it defines the orientation ID and the orientation values.

// Orientations.
public const int OrientationId = 0x0112;
public enum ExifOrientations
{
    Unknown = 0,
    TopLeft = 1,
    TopRight = 2,
    BottomRight = 3,
    BottomLeft = 4,
    LeftTop = 5,
    RightTop = 6,
    RightBottom = 7,
    LeftBottom = 8,
}

The following code shows how the program gets the image’s orientation.

// Return the image's orientation.
public static ExifOrientations ImageOrientation(Image img)
{
    // Get the index of the orientation property.
    int orientation_index =
        Array.IndexOf(img.PropertyIdList, OrientationId);

    // If there is no such property, return Unknown.
    if (orientation_index < 0) return ExifOrientations.Unknown;

    // Return the orientation value.
    return (ExifOrientations)
        img.GetPropertyItem(OrientationId).Value[0];
}

This code uses Array.IndexOf to see if the image's property ID list includes orientation. If the orientation ID is found, the method uses GetPropertyItem to get the corresponding PropertyItem object, gets its first Value entry, converts it into an ExifOrientations value, and returns the result.

The ExifStuff class also contains the following OrientationImage method, which returns an image showing the letter F in a particular orientation. You can download the example program that generated the orientation images shown earlier here. Look at that example's code to see how it works.

// Make an image to demonstrate orientations.
public static Image OrientationImage(ExifOrientations orientation)
{
    const int size = 64;
    Bitmap bm = new Bitmap(size, size);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.Clear(Color.White);
        gr.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

        // Orient the result.
        switch (orientation)
        {
            case ExifOrientations.TopLeft:
                break;
            case ExifOrientations.TopRight:
                gr.ScaleTransform(-1, 1);
                break;
            case ExifOrientations.BottomRight:
                gr.RotateTransform(180);
                break;
            case ExifOrientations.BottomLeft:
                gr.ScaleTransform(1, -1);
                break;
            case ExifOrientations.LeftTop:
                gr.RotateTransform(90);
                gr.ScaleTransform(-1, 1, MatrixOrder.Append);
                break;
            case ExifOrientations.RightTop:
                gr.RotateTransform(-90);
                break;
            case ExifOrientations.RightBottom:
                gr.RotateTransform(90);
                gr.ScaleTransform(1, -1, MatrixOrder.Append);
                break;
            case ExifOrientations.LeftBottom:
                gr.RotateTransform(90);
                break;
        }

        // Translate the result to the center of the bitmap.
        gr.TranslateTransform(
            size / 2, size / 2, MatrixOrder.Append);

        using (StringFormat string_format = new StringFormat())
        {
            string_format.LineAlignment = StringAlignment.Center;
            string_format.Alignment = StringAlignment.Center;
            using (Font font = new Font("Times New Roman", 40,
                GraphicsUnit.Point))
            {
                if (orientation == ExifOrientations.Unknown)
                {
                    gr.DrawString("?", font, Brushes.Black,
                        0, 0, string_format);
                }
                else
                {
                    gr.DrawString("F", font, Brushes.Black,
                        0, 0, string_format);
                }
            }
        }
    }

    return bm;
}

This method demonstrates some interesting graphics transformations. First it creates a Bitmap and an associated Graphics object. Then depending on the desired orientation, it applies a transformation to the Graphics object to appropriately rotate and flip the drawing that follows.

Next the code applies a translation to center the resulting image in the Bitmap. Finally the method draws the letter F centered at the origin. The transformations rotate and flip the result and then translate it to center it in the Bitmap.

The main example program uses the ExifStuff methods in the following code to display an image, its orientation, and an oriented sample image containing the letter F.

// Open the file and read its orientation information.
private void btnOpen_Click(object sender, EventArgs e)
{
    // Open the file.
    Bitmap bm = new Bitmap(txtFile.Text);
    picOriginal.Image = bm;

    // Get the PropertyItems property from image.
    ExifStuff.ExifOrientations orientation =
        ExifStuff.ImageOrientation(bm);
    lblOrientation.Text = orientation.ToString();
    picOrientation.Image = ExifStuff.OrientationImage(orientation);
}

The code opens a JPG file and displays it. Next it then calls ExifStuff.ImageOrientation to get the image's orientation and displays it as a string. It finishes by calling ExifStuff.OrientationImage to get the oriented sample image and it displays the returned image.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in files, graphics, image processing and tagged , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Read an image file’s EXIF orientation data in C#

  1. jessica says:

    The images of #6 RightTop and #8 LeftBottom should be switch.

  2. Rod Stephens says:

    Unless I’m misunderstanding something, I think this is correct. It agrees with these pages:

    But as I said, perhaps I’m misunderstanding.

  3. Pingback: Use EXIF information to orient an image in C# - C# HelperC# Helper

Leave a Reply

Your email address will not be published. Required fields are marked *