画像(JPEG)から位置情報を取得

C#で JPEG の Exifデータ にある GPS情報(位置情報)を取得します。今回は、GPS情報のうち下記の4つを取得しています。

タグ名称 タグ番号 Field Name タイプ
北緯(N)or 南緯(S)  1 GPSLatitudeRef  ASCII
緯度(数値)  2 GPSLatitude  RATIONAL
東経(E)or 西経(W)  3 GPSLongitudeRef  ASCII
経度(数値)  4 GPSLongitude  RATIONAL

※RATIONAL : 最初の数値が分子、2個目の数値が分母を表す 32 ビット符号なし整数が2個

Exifの詳しい仕様についてはJEITAをご覧ください。

http://www.jeita.or.jp/japanese/index.cgi

 

Bitmap クラス オブジェクトを作成し、タグ番号(Id)の配列を取得します。

System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fn);
int[] ids = bmp.PropertyIdList;

 

緯度の南北を文字列として取得します。

int index = Array.IndexOf(ids, 0x0001);
System.Drawing.Imaging.PropertyItem item = bmp.PropertyItems[index];
string s = BitConverter.ToChar(item.Value, 0).ToString();

 

緯度を取得します。緯度は、度、分、秒3つの RATIONALとなっています。ただし、DMM形式又はDMS形式となっていますので、今回は形式を統一するためDMM形式の場合は、DMS形式に変換します。

DMS形式の場合は、そのまま割り算すれば取得できます。

int index = Array.IndexOf(ids, 0x0002);
System.Drawing.Imaging.PropertyItem item = bmp.PropertyItems[index];
double dd = BitConverter.ToUInt32(item.Value, 0) / BitConverter.ToUInt32(item.Value, 4);
double mm = BitConverter.ToUInt32(item.Value, 8) / BitConverter.ToUInt32(item.Value, 12);
double ss = (double)BitConverter.ToUInt32(item.Value, 16) / (double)BitConverter.ToUInt32(item.Value, 20);

 

DMM形式の場合は、度はそのまま割り算し、分は割り算の結果の整数部分のみ、秒は分の小数点以下に60を掛けて計算します。

int index = Array.IndexOf(ids, 0x0002);
System.Drawing.Imaging.PropertyItem item = bmp.PropertyItems[index];
double dd = BitConverter.ToUInt32(item.Value, 0) / BitConverter.ToUInt32(item.Value, 4);
double mmmm = (double)BitConverter.ToUInt32(item.Value, 8) / (double)BitConverter.ToUInt32(item.Value, 12);
double ss = (mmmm % 1) * 60;
double mm = (UInt32)mmmm;

 

DMS形式とDMM形式の判断は、分の分母で判断できます(DMM形式の場合は「100」)。

if (BitConverter.ToUInt32(item.Value, 12) == 100) {
	・・・・
}

 

東経(E)or 西経(W), 経度も同様に取得することができます。

また、緯度・経度共に百分率で表示する場合は、「度 + (分 / 60) + (秒 / 3600)」で計算します。

 

サンプルコード

using System;
using System.Windows.Forms;

namespace Test
{

    public partial class Form1 : Form
    {
        public class Point
        {
            public string r { get; set; }
            public double dd { get; set; }
            public double mm { get; set; }
            public double ss { get; set; }

            public double per
            {
                get
                {
                    return dd + (mm / 60) + (ss / 3600);
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Point lat = new Point();
            Point lon = new Point();

            string fn = "ファイル名";

            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fn);
            int[] ids = bmp.PropertyIdList;

            // 緯度の南北(タグ番号 1.GPSLatitudeRef)を取得
            System.Drawing.Imaging.PropertyItem gpsLatitudeRef = 
                bmp.PropertyItems[Array.IndexOf(ids, 0x0001)];
            lat.r = BitConverter.ToChar(gpsLatitudeRef.Value, 0).ToString();

            // 緯度(タグ番号 2.GPSLatitude)を取得
            System.Drawing.Imaging.PropertyItem gpsLatitude = 
                bmp.PropertyItems[Array.IndexOf(ids, 0x0002)];
            lat.dd = BitConverter.ToUInt32(gpsLatitude.Value, 0) / BitConverter.ToUInt32(gpsLatitude.Value, 4);
            if (BitConverter.ToUInt32(gpsLatitude.Value, 12) == 100)
            {
                // DMM形式 → DMS形式
                double mmmmm = (double)BitConverter.ToUInt32(gpsLatitude.Value, 8) / (double)BitConverter.ToUInt32(gpsLatitude.Value, 12);
                lat.ss = (mmmmm % 1) * 60;
                lat.mm = (UInt32)mmmmm;
            }
            else
            {
                // DMS形式
                lat.mm = BitConverter.ToUInt32(gpsLatitude.Value, 8) / BitConverter.ToUInt32(gpsLatitude.Value, 12);
                lat.ss = (double)BitConverter.ToUInt32(gpsLatitude.Value, 16) / (double)BitConverter.ToUInt32(gpsLatitude.Value, 20);
            }


            // 経度の東西(タグ番号 3.GPSLongitudeRef)を取得
            System.Drawing.Imaging.PropertyItem gpsLongitudeRef = bmp.PropertyItems[Array.IndexOf(ids, 0x0003)];
            lon.r = BitConverter.ToChar(gpsLongitudeRef.Value, 0).ToString();

            // 経度(タグ番号 4.GPSLongitude)を取得
            System.Drawing.Imaging.PropertyItem gpsLongitude = bmp.PropertyItems[Array.IndexOf(ids, 0x0004)];
            lon.dd = BitConverter.ToUInt32(gpsLongitude.Value, 0) / BitConverter.ToUInt32(gpsLongitude.Value, 4);

            if (BitConverter.ToUInt32(gpsLongitude.Value, 12) == 100)
            {
                // DMM形式 → DMS形式
                double mmmmm = (double)BitConverter.ToUInt32(gpsLongitude.Value, 8) / (double)BitConverter.ToUInt32(gpsLongitude.Value, 12);
                lon.ss = (mmmmm % 1) * 60;
                lon.mm = (UInt32)mmmmm;
            }
            else
            {
                // DMS形式
                lon.mm = BitConverter.ToUInt32(gpsLongitude.Value, 8) / BitConverter.ToUInt32(gpsLongitude.Value, 12);
                lon.ss = (double)BitConverter.ToUInt32(gpsLongitude.Value, 16) / (double)BitConverter.ToUInt32(gpsLongitude.Value, 20);
            }

            textBox1.Text += string.Format("{0}{1}°{2} {3}rn", lat.r, lat.dd, lat.mm, lat.ss);
            textBox1.Text += string.Format("{0}{1}°{2} {3}rn", lon.r, lon.dd, lon.mm, lon.ss);

            // 百分率表記
            textBox1.Text += string.Format("{0}rn", lat.per);
            textBox1.Text += string.Format("{0}rn", lon.per);

            bmp.Dispose();
        }

        public Form1()
        {
            InitializeComponent();
        }
    }
}

Comments are closed.

Post Navigation