分类
C# Develop

EXIF information for photo

In windows, when you look at the details of a photo, there are a lot of information there:

捕获1

捕获2

捕获3

Recently, I want to parse them out of photo in application, but there is little article about this. So I did an experiment with C# and got all of the mappings and recorded here.

EXIF schema

EXIF information is stored in the binary of photo like jpg format. Each of them stored with
1. ID, int type, id of this information
2. Length, int type, indicate the length of the value
3. Type, short type, indicate the type of the value, this is important to translate the value. This is the MSDN document for it.
4. Value, an array of binary, stored the actual value.

IDs mapping to windows attributes

Included the ones that difficult to find, like subject, rating, notes and tags (0x9c__)

Meaning of id ID Notes
title 0x10e and 0x9c9b
subject 0x9c9f
rating 0x4746 value in (null,1-5)
rating 0x4749 value in (null,1-99)
tags 0x9c9e if more than 1 tag, will separate by ;
notes 0x9c9c
author 0x13b and 0x9c9d if more than 1 tag, will separate by ;
original time 0x9003
digitalized 0x9004 in windows, combine with 0x9003
copyright 0x8298
width 0xa002
height 0xa003

In windows attributes window, change the Capture time or 拍摄时间 will change 0x9003 and 0x9004;
Change rating will modify 0x4746 and 0x4749(null, 1, 25, 50, 75, 99);
Change title will modify 0x10e and 0x9c9b;
Change author will modify 0x13b and 0x9c9d.
And 0x9c__ ids are of type 1, and further as Unicode string.

Types of attributes

  • 1 is binary array, but may be is Unicode string, like 0x9c9b – 0x9c9f
  • 2 is ASCII string with null-terminator.
  • 3 is short, 16-bit integer.
  • 4 is long, 32-bit integer.
  • 5 is array of fractions, first 32-bit is the unsigned long numerator, second 32-bit is denominator.
  • 6 is binary array.
  • 7 is array of signed long (32-bit) integer.
  • 10 is array of pairs of signed long integers. each pair is fraction, just like 5.

Code

//Please ignore the ListView things, I use them to check those data.
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
//通过指定的数据流来创建Image
System.Drawing.Image image = System.Drawing.Image.FromStream(stream, true, false);
foreach (System.Drawing.Imaging.PropertyItem item in image.PropertyItems)
{
    ListViewItem lvItem = new ListViewItem("0x" + item.Id.ToString("x"));
    lvItem.SubItems.Add(item.Type.ToString());
    lvItem.SubItems.Add(item.Len.ToString());
    if (item.Type == 1)
    {
        string v = System.Text.ASCIIEncoding.Unicode.GetString(item.Value);
        v = v.Substring(0, Math.Min(100, v.Length));
        lvItem.SubItems.Add(v.ToString());
    }
    else
    if (item.Type == 2 || item.Type == 7)
    {
        lvItem.SubItems.Add(Encoding.UTF8.GetString(item.Value));
    }
    else if (item.Type == 3)
    {
        Int16 v = System.BitConverter.ToInt16(item.Value, 0);
        lvItem.SubItems.Add(v.ToString());
    }
    else if (item.Type == 4)
    {
        Int32 v = System.BitConverter.ToInt32(item.Value, 0);
        lvItem.SubItems.Add(v.ToString());
    }
    else if (item.Type == 5)
    {
        Int32 upper = System.BitConverter.ToInt32(item.Value, 0);
        Int32 lower = System.BitConverter.ToInt32(item.Value, 4);
        lvItem.SubItems.Add(upper + "/" + lower);
    }
    else if (item.Type == 9)
    {
        Int64 v = System.BitConverter.ToInt64(item.Value, 0);
        lvItem.SubItems.Add(v.ToString());
    }
    else if (item.Type == 10)
    {
        double v = System.BitConverter.ToDouble(item.Value, 0);
        lvItem.SubItems.Add(v.ToString());
    }
    else
    {
        string v = System.BitConverter.ToString(item.Value);
        v = v.Substring(0, Math.Min(100, v.Length));
        lvItem.SubItems.Add(v);
    }

    listView1.Items.Add(lvItem);
}

Reference

MSDN PropertyItem definition
Additional Ids definition

发表评论

电子邮件地址不会被公开。 必填项已用*标注