WinRT APIを使って画像ファイルの位置情報を編集する

WinRT APIには、画像ファイルの位置情報を取り出すAPIが用意されています。

位置情報を取り出すのはとても簡単で、imageFileをStorageFile型のオブジェクトとすると、

        var imageProps = await imageFile.Properties.GetImagePropertiesAsync();

で、imagePropsのLatitude、Longitudeから緯度、経度を取得可能です。この二つのプロパティの型は、double?で、Nulable型になっています。画像ファイルに位置情報が付与されていない場合には、この二つの値はnullです。加えて、この二つのプロパティは、Readonlyで書き換えができません。Windows Phoneデバイスのカメラでは、位置情報を付与してJPEGファイルとして保存することができますが、多分、位置情報付きの画像ファイルはそれほど多くはないのではないかと思われます。位置情報が付与されているのであれば、既にストアから公開(https://apps.microsoft.com/windows/app/f7f0662c-ba9d-4bb3-a6d5-a1559c970aeb )されている、”どこの写真”アプリの様に、

と、写真を地図上に撮った位置にマップして表示する事ができたりするので、色々と便利なんですね。画像ファイルのデータをバイナリレベルで色々と弄れば位置情報を編集するのは可能なのですが、WinRT APIで変更する方法はないかな…と探していたところ、やり方がForum上で公開されているのを見つけました。情報元はこちら。

https://social.msdn.microsoft.com/Forums/nl/winappswithcsharp/thread/aaf0b373-b0e0-4d91-84d8-69e768a374d8

LatitudeとLongitudeを、そのまま保持しているのではなく、別の形式のデータから計算して取得しているので直接はかえられないみたいですね。内部の形式は、上のURLからたどって調べてもらうとして、以下に画像ファイルの位置情報を編集するコードの例を挙げておきますね。

    class LocationHelper
    {
        public static async Task<ImageProperties> AddLocation(StorageFile imageFile, double latitude, double longitude)
        {
            int[] denomitor = new int[3] { 1, 1, 1000 };
            string latitudeRef = "N";
            if (latitude < 0)
            {
                latitudeRef = "S";
                latitude *= -1;
            }
            string longitudeRef = "E";
            if (longitude < 0)
            {
                longitudeRef = "W";
                longitude *= -1;
            }

            int[] latitudeNumerator = new int[3] { 0, 0, 0 };
            int[] longitudeNumerator = new int[3] { 0, 0, System.GPS.LatitudeNumerator0 };

            Calcurate(latitude, denomitor, ref latitudeNumerator);
            Calcurate(longitude, denomitor, ref longitudeNumerator);

            var props = new List<KeyValuePair<string, object>>();
            props.Add(new KeyValuePair<string, object>("System.GPS.LongitudeNumerator", longitudeNumerator));
            props.Add(new KeyValuePair<string, object>("System.GPS.LongitudeDenominator", denomitor));
            props.Add(new KeyValuePair<string, object>("System.GPS.LongitudeRef", longitudeRef));
            props.Add(new KeyValuePair<string, object>("System.GPS.LatitudeNumerator", latitudeNumerator));
            props.Add(new KeyValuePair<string, object>("System.GPS.LatitudeDenominator", denomitor));
            props.Add(new KeyValuePair<string, object>("System.GPS.LatitudeRef", latitudeRef));

            await imageFile.Properties.SavePropertiesAsync(props);
            var imageProps = await imageFile.Properties.GetImagePropertiesAsync();
            return imageProps;
        }

        private static void Calcurate(double val, int[] denomitor, ref int[] numerator)
        {
            numerator[0] = (int)System.Math.Floor(val);
            val -= numerator[0];
            if (val >= 0)
            {
                val *= 60;
                numerator[1] = (int)System.Math.Floor(val);
                val -= numerator[1];
                if (val >= 0)
                {
                    val *= 60;
                    numerator[2] = (int)(System.Math.Round(val * denomitor[2]));
                }
                else
                {
                    numerator[2] = 0;
                }
            }
            else
            {
                numerator[1] = 0;
                numerator[2] = 0;
            }
        }
    }

内部形式は、方位と度、分、秒を基本としたデータ構造ってわけです。更新の際に使われているキーワードは、

https://msdn.microsoft.com/en-us/library/windows/desktop/ff514245(v=vs.85).aspx

に載っているものが使われています。

以上、画像ファイルの位置情報に関するTipsでした。