[C# Helper]
Index Books FAQ Contact About Rod
[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[Beginning Software Engineering]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Make an enumeration of EXIF property IDs in C#

[Make an enumeration of EXIF property IDs in C#]

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 the example to experiment with it and to see additional details.

© 2009-2022 Rocky Mountain Computer Consulting, Inc. All rights reserved.