Make an enumeration of EXIF property IDs in C#

[EXIF property IDs ]

This post is really a helper program that lists EXIF property IDs for the following post. To get an EXIF image’s properties, you read through a list of EXIF property IDs and examine their values. The IDs are numeric so, to really do this meaningfully, you need to know the names of the properties that go with the numeric values.

You can find lists of the values on various web pages. I didn’t find any page that contains a complete list. The list may change over time so it’s possible that there will never be a perfect list, but I did find some good incomplete lists on these sites:

Each of the lists comes as in HTML table. To gather the data, I used the mouse to select the table and then pasted it into Microsoft Word. I then uses Word to convert the table into text with delimited fields. Finally I saved the data in a text file. Here’s what three data files looked like.

Microsoft:

0x0000 | GpsVer
0x0001 | GpsLatitudeRef
0x0002 | GpsLatitude

AWARE[SYSTEMS]:

33434	829A	ExposureTime	Exposure time, given in seconds.
33437	829D	FNumber	The F number.
34850	8822	ExposureProgram	The class of the program used by the camera to set exposure when the picture is taken.

Exiv2:

0x000b	11	Image	Exif.Image.ProcessingSoftware	Ascii	The name and version of the software used to post-process the picture.
0x00fe	254	Image	Exif.Image.NewSubfileType	Long	A general indication of the kind of data contained in this subfile.
0x00ff	255	Image	Exif.Image.SubfileType	Short	A general indication of the kind of data contained in this subfile. This field is 

Now we get to how this example program works. Its job is to load the values in each of these data sources. If a value has already been read, the program should skip it.

The following ProcessIdFile method reads a delimited file and saves property names and IDs.

// Holds an EXIF property value's name and ID.
private Dictionary Ids;

// Process values from a delimited data file.
private void ProcessIdFile(string filename,
    char[] delimiters, int id_field, int name_field)
{
    // Get the data from the file.
    string[] data = File.ReadAllLines(filename);
    int num_used = 0;
    int num_unused = 0;
    foreach (string line in data)
    {
        string[] fields = line.Split(delimiters,
            StringSplitOptions.RemoveEmptyEntries);

        if (fields.Length > 0)
        {
            string id_string =
                fields[id_field].ToLower().Replace("0x", "");
            short property_id = short.Parse(
                id_string, NumberStyles.HexNumber);
            if (Ids.ContainsKey(property_id))
                num_unused++;
            else
            {
                num_used++;
                string property_name = fields[name_field];
                Ids.Add(property_id, property_name);
            }
        }
    }
    txtStatus.AppendText(filename + '\n');
    txtStatus.AppendText("    # Used: " + num_used + '\n');
    txtStatus.AppendText("    # Unused: " + num_unused + '\n');
}

The Ids dictionary will hold the property IDs (keys) and names (values).

The ProcessIdFile method takes as parameters the name of the file to process, an array of characters that delimit the file’s fields (spaces or tabs), and the indices of the property ID and name columns in the file.

The method first reads all of the file’s lines of text into an array. Then for each line it uses the separator array to break the line into fields and then parses the ID field. If the ID is not yet in the Ids dictionary, the method adds it.

The following code shows how the program uses the ProcessIdFile method.

// Process the enum data.
private void btnProcess_Click(object sender, EventArgs e)
{
    txtStatus.Clear();
    Ids = new Dictionary();

    // Process the ID data files.
    // Microsoft.
    ProcessIdFile("data_microsoft.txt", new char[] { ' ' }, 0, 2);

    // AWARE[SYSTEMS]
    ProcessIdFile("data_aware_systems.txt",
        new char[] { '\t' }, 1, 2);

    // Exiv2
    ProcessIdFile("data_exiv2.txt", new char[] { '\t' }, 0, 3);

    // Sort the values by ID.
    StringBuilder sb = new StringBuilder();
    foreach (KeyValuePair<short, string> pair
        in Ids.OrderBy(x => x.Key.ToString("x4")))
    {
        // Add this value to the result.
        string id_string = pair.Key.ToString("x4");
        string id_name = pair.Value.Replace('.', '_');
        sb.AppendLine("            " +
            id_name + " = 0x" + id_string + ",");
    }

    // Save the resulting enum in a file.
    string result = "        public enum ExifPropertyTypes\n";
    result += "        {\n";
    result += sb.ToString();
    result += "        }\n";
    File.WriteAllText("exif_property_ids.txt", result);
}

The method clears its output TextBox and creates a new Ids dictionary. It then calls ProcessIdFile to process the three data files.

At this point the Ids dictionary holds the property IDs and names. We need to process them sorted by ID.

To do that, the code uses the dictionary LINQ extension method OrderBy. It passes that method the lambda expression x => x.Key.ToString("x4"). The OrderBy method uses that lambda expression on the KeyValuePair objects contained by the dictionary to order them by Key.

The lambda expression converts the key values into hexadecimal to make the sort order make sense. Some of the key values are negative when viewed as short values so sorting them numerically makes those come before others such as 0001. Then when they are converted into hexadecimal, the results seem out of order. Making the lambda expression convert them into hexadecimal avoids the whole issue.

The code loops through the ordered KeyValuePair objects. For each pair, it adds a string of the form Name = 0x1234 to the StringBuilder named sb.

Finally the code uses the StringBuilder and some literal text to format a C# enum and writes it into the file exif_property_ids.txt. The following text shows the resulting file’s format.

public enum ExifPropertyTypes
{
    GpsVer = 0x0000,
    GpsLatitudeRef = 0x0001,
    GpsLatitude = 0x0002,
    GpsLongitudeRef = 0x0003,
    ...
    Exif_Image_OpcodeList3 = 0xc74e,
    Exif_Image_NoiseProfile = 0xc761,
}

My next post uses this enumeration to display the EXIF property IDs, names, and values for an image.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.

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

One Response to Make an enumeration of EXIF property IDs in C#

  1. Pingback: List an image's EXIF properties in C# - C# HelperC# Helper

Leave a Reply

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