Search code examples
iosxamarin.iosxamarin.formsxamarin-studioxamarin.mac

Longitude is always zero in image meta data


I am taking a photo using a MediaPicker in Xamarin. I start the geolocation service and then once the picture is taken I send the byte array of the image and the position information to my own platform specific implementation to add the position information in the meta data of the image.

I then save the image as a file and then email it to myself so I can open it in an external application (Picasa) to ensure the GPS information has been stored properly.

The problem I am running into is that the Latitude and Altitude show up fine, but the Longitude is always zero. I have put break points in my app and verified that the meta data is set properly and that all the information has valid values. I am at a loss at what is going on here.

Some of the following code may be redundant or inefficient simply because I have been testing different methods of adding the meta data. I am using the following code in my application in iOS implementation of this meta data adding method:

public byte[] AddPositionInformation(byte[] bytes, SaleScribe.PCL.Services.Geolocation.Position position)
    {
        var data = NSData.FromArray(bytes);

        UIKit.UIImage original = UIKit.UIImage.LoadFromData(data);
        CGImageSource myImageSource = CGImageSource.FromData(original.AsJPEG());

        var options = new CGImageDestinationOptions();
        options.GpsDictionary = new CoreGraphics.CGImagePropertiesGps();
        options.GpsDictionary.Latitude = (float)position.Latitude;
        options.GpsDictionary.Longitude = (float)position.Longitude;
        options.GpsDictionary.Altitude = (int)position.Altitude;

        NSMutableData mutableData = new NSMutableData();
        using(var dest = CGImageDestination.Create(mutableData, myImageSource.TypeIdentifier, 1, new CGImageDestinationOptions()))
        {
            dest.AddImage(myImageSource, (int)(myImageSource.ImageCount - 1), options);
            dest.Close();
        }

        return (mutableData as NSData).ToArray();
}

In the function that receives this byte array I am simply writing the byte array directly to a file.

Any help would be very much appreciated.

Thanks!


Solution

  • For anyone who may interested I had to use another method to get this to work, but the underlying problem was that the GPS Lat and Long require a uint so the -94.xxx longitude was invalid. I needed to add the absolute value of the lat and long and then add the appropriate ref value based on the original signed value.

    Here is the code that worked for me:

    public byte[] AddPositionInformation(byte[] bytes, SaleScribe.PCL.Services.Geolocation.Position position)
        {
            var data = NSData.FromArray(bytes);
    
            CGImageSource myImageSource = CGImageSource.FromData(data);
            var ns = new NSDictionary();
            var imageProperties = myImageSource.CopyProperties(ns, 0);
    
            var gps = new NSMutableDictionary();
            gps.SetValueForKey(NSObject.FromObject(System.Math.Abs(position.Latitude)), CGImageProperties.GPSLatitude);
            gps.SetValueForKey(NSObject.FromObject(new NSString(position.Latitude < 0 ? "S" : "N")), CGImageProperties.GPSLatitudeRef);
    
            gps.SetValueForKey(NSObject.FromObject(System.Math.Abs(position.Longitude)), CGImageProperties.GPSLongitude);
            gps.SetValueForKey(NSObject.FromObject(new NSString(position.Longitude < 0 ? "W" : "E")), CGImageProperties.GPSLongitudeRef);
    
            gps.SetValueForKey(NSObject.FromObject(position.Altitude), CGImageProperties.GPSAltitude);
            gps.SetValueForKey(NSObject.FromObject(position.Altitude < 0 ? 1 : 0), CGImageProperties.GPSAltitudeRef);
    
            var mutableDictionary = imageProperties.MutableCopy();
            mutableDictionary.SetValueForKey(gps, CGImageProperties.GPSDictionary);
    
            NSMutableData mutableData = new NSMutableData();
            var dest = CGImageDestination.Create(mutableData, myImageSource.TypeIdentifier, 1);
            dest.AddImage(myImageSource, 0, mutableDictionary as NSDictionary);
            dest.Close();
    
            return mutableData.ToArray();
        }