Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8700389
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T02:09:31+00:00 2026-06-13T02:09:31+00:00

After countless attempts and sieving through every SO answer + google result, it baffles

  • 0

After countless attempts and sieving through every SO answer + google result, it baffles me that working with EXIF on iOS is so frustrating.

Below is working code with its results.

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
    completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
    {
        NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

        CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL);

        //get all the metadata in the image
        NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL);

        NSLog(@"original metadata Info: %@",metadata);

        //make the metadata dictionary mutable so we can add properties to it
        NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];

        NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy];
        NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy];
        NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy];

        if(!EXIFDictionary)
            EXIFDictionary = [[NSMutableDictionary dictionary] init];

        if(!GPSDictionary)
            GPSDictionary = [[NSMutableDictionary dictionary] init];

        if(!RAWDictionary)
            RAWDictionary = [[NSMutableDictionary dictionary] init];


        [GPSDictionary setObject:@"camera coord Latitude"
                         forKey:(NSString*)kCGImagePropertyGPSLatitude];
        [GPSDictionary setObject:@"camera coord Longitude"
                         forKey:(NSString*)kCGImagePropertyGPSLongitude];
        [GPSDictionary setObject:@"camera GPS Date Stamp"
                         forKey:(NSString*)kCGImagePropertyGPSDateStamp];
        [GPSDictionary setObject:@"camera direction (heading) in degrees"
                         forKey:(NSString*)kCGImagePropertyGPSImgDirection];

        [GPSDictionary setObject:@"subject coord Latitude"
                         forKey:(NSString*)kCGImagePropertyGPSDestLatitude];
        [GPSDictionary setObject:@"subject coord Longitude"
                         forKey:(NSString*)kCGImagePropertyGPSDestLongitude];

        [EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment"
                           forKey:(NSString *)kCGImagePropertyExifUserComment];

        [EXIFDictionary setValue:@"69 m" forKey:(NSString *)kCGImagePropertyExifSubjectDistance];


        //Add the modified Data back into the image’s metadata
        [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
        [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
        [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary];


        NSLog(@"metadataAsMutable Info: %@",metadataAsMutable);

        CFStringRef UTI = CGImageSourceGetType(imgSource); //this is the type of image (e.g., public.jpeg)

        //this will be the data CGImageDestinationRef will write into
        NSMutableData *newImageData = [NSMutableData data];

        CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, UTI, 1, NULL);

        if(!destination)
            NSLog(@"***Could not create image destination ***");

        //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
        CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef) metadataAsMutable);

        //tell the destination to write the image data and metadata into our data object.
        //It will return false if something goes wrong
        BOOL success = NO;
        success = CGImageDestinationFinalize(destination);

        if(!success)
            NSLog(@"***Could not create data from image destination ***");

        CIImage *testImage = [CIImage imageWithData:newImageData];
        NSDictionary *propDict = [testImage properties];
        NSLog(@"Properties %@", propDict);

    }];

Which outputs this:

2012-10-12 23:17:45.415 Waypointer[3120:907] original metadata Info: {
ColorModel = RGB;
DPIHeight = 72;
DPIWidth = 72;
Depth = 8;
Orientation = 1;
PixelHeight = 2448;
PixelWidth = 3264;
"{Exif}" =     {
    ApertureValue = "2.526069";
    BrightnessValue = "-4.410617";
    ColorSpace = 1;
    ComponentsConfiguration =         (
        1,
        2,
        3,
        0
    );
    ExifVersion =         (
        2,
        2,
        1
    );
    ExposureMode = 0;
    ExposureProgram = 2;
    ExposureTime = "0.06666667";
    FNumber = "2.4";
    Flash = 16;
    FlashPixVersion =         (
        1,
        0
    );
    FocalLenIn35mmFilm = 35;
    FocalLength = "4.28";
    ISOSpeedRatings =         (
        800
    );
    MeteringMode = 5;
    PixelXDimension = 3264;
    PixelYDimension = 2448;
    SceneCaptureType = 0;
    SensingMethod = 2;
    ShutterSpeedValue = "3.906905";
    SubjectArea =         (
        1631,
        1223,
        881,
        881
    );
    WhiteBalance = 0;
};
"{TIFF}" =     {
    Orientation = 1;
    ResolutionUnit = 2;
    XResolution = 72;
    YResolution = 72;
    "_YCbCrPositioning" = 1;
};
}

And this:

2012-10-12 23:17:45.421 Waypointer[3120:907] metadataAsMutable Info: {
ColorModel = RGB;
DPIHeight = 72;
DPIWidth = 72;
Depth = 8;
Orientation = 1;
PixelHeight = 2448;
PixelWidth = 3264;
"{Exif}" =     {
    ApertureValue = "2.526069";
    BrightnessValue = "-4.410617";
    ColorSpace = 1;
    ComponentsConfiguration =         (
        1,
        2,
        3,
        0
    );
    ExifVersion =         (
        2,
        2,
        1
    );
    ExposureMode = 0;
    ExposureProgram = 2;
    ExposureTime = "0.06666667";
    FNumber = "2.4";
    Flash = 16;
    FlashPixVersion =         (
        1,
        0
    );
    FocalLenIn35mmFilm = 35;
    FocalLength = "4.28";
    ISOSpeedRatings =         (
        800
    );
    MeteringMode = 5;
    PixelXDimension = 3264;
    PixelYDimension = 2448;
    SceneCaptureType = 0;
    SensingMethod = 2;
    ShutterSpeedValue = "3.906905";
    SubjectArea =         (
        1631,
        1223,
        881,
        881
    );
    SubjectDistance = "69 m";
    UserComment = "[S.D.] kCGImagePropertyExifUserComment";
    WhiteBalance = 0;
};
"{GPS}" =     {
    DateStamp = "camera GPS Date Stamp";
    DestLatitude = "subject coord Latitude";
    DestLongitude = "subject coord Longitude";
    ImgDirection = "camera direction (heading) in degrees";
    Latitude = "camera coord Latitude";
    Longitude = "camera coord Longitude";
};
"{Raw}" =     {
};
"{TIFF}" =     {
    Orientation = 1;
    ResolutionUnit = 2;
    XResolution = 72;
    YResolution = 72;
    "_YCbCrPositioning" = 1;
};
}

And, after it’s all done, this:

2012-10-12 23:17:47.131 Waypointer[3120:907] Properties {
ColorModel = RGB;
DPIHeight = 72;
DPIWidth = 72;
Depth = 8;
Orientation = 1;
PixelHeight = 2448;
PixelWidth = 3264;
"{Exif}" =     {
    ApertureValue = "2.526069";
    BrightnessValue = "-4.410617";
    ColorSpace = 1;
    ComponentsConfiguration =         (
        0,
        0,
        0,
        1
    );
    ExifVersion =         (
        2,
        2,
        1
    );
    ExposureMode = 0;
    ExposureProgram = 2;
    ExposureTime = "0.06666667";
    FNumber = "2.4";
    Flash = 16;
    FlashPixVersion =         (
        1,
        0
    );
    FocalLenIn35mmFilm = 35;
    FocalLength = "4.28";
    ISOSpeedRatings =         (
        800
    );
    MeteringMode = 5;
    PixelXDimension = 3264;
    PixelYDimension = 2448;
    SceneCaptureType = 0;
    SensingMethod = 2;
    ShutterSpeedValue = "3.906905";
    SubjectArea =         (
        1631,
        1223,
        881,
        881
    );
    UserComment = "[S.D.] kCGImagePropertyExifUserComment";
    WhiteBalance = 0;
};
"{JFIF}" =     {
    DensityUnit = 1;
    JFIFVersion =         (
        1,
        1
    );
    XDensity = 72;
    YDensity = 72;
};
"{TIFF}" =     {
    Orientation = 1;
    ResolutionUnit = 2;
    XResolution = 72;
    YResolution = 72;
    "_YCbCrPositioning" = 1;
};
}

As the example illustrates, you can see the image’s original metaData, its modification, and then its final output.

The final output is what bothers me because no matter what I do, I cannot get my modified values to stick!

Is there some very specific format I’m missing?
Why is iOS stripping my modifications?
What do I need to do to add these extra values? They are listed in the .header and figured it should be easily accepted.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T02:09:32+00:00Added an answer on June 13, 2026 at 2:09 am

    Scott, a developer at Apple, returned with my incident report and fixed the issue:

    The previous code above is writing string values for the GPS
    values – this won’t work, they must be NS/CFNumbers (we extract
    a float value for EXIF).

    I’ll be filing a bug report to Apple against their documentation.

    Although it took a week to get this response, I really do appreciate the support Apple provides to their developers. (thanks Scott!) 😉

    Below is the improved code and its correct output:

    [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
        completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
        {
            NSData *imageNSData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
    
            CGImageSourceRef imgSource = CGImageSourceCreateWithData((__bridge_retained CFDataRef)imageNSData, NULL);
    
            //get all the metadata in the image
            NSDictionary *metadata = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imgSource, 0, NULL);
    
            //make the metadata dictionary mutable so we can add properties to it
            NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];
    
            NSMutableDictionary *EXIFDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy];
            NSMutableDictionary *GPSDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy];
            NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy];
    
            if(!EXIFDictionary)
                EXIFDictionary = [[NSMutableDictionary dictionary] init];
    
            if(!GPSDictionary)
                GPSDictionary = [[NSMutableDictionary dictionary] init];
    
            if(!RAWDictionary)
                RAWDictionary = [[NSMutableDictionary dictionary] init];
    
    
            [GPSDictionary setObject:[NSNumber numberWithFloat:37.795]
                              forKey:(NSString*)kCGImagePropertyGPSLatitude];
    
            [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
    
            [GPSDictionary setObject:[NSNumber numberWithFloat:122.410]
                              forKey:(NSString*)kCGImagePropertyGPSLongitude];
    
            [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
    
            [GPSDictionary setObject:@"2012:10:18"
                              forKey:(NSString*)kCGImagePropertyGPSDateStamp];
    
            [GPSDictionary setObject:[NSNumber numberWithFloat:300]
                              forKey:(NSString*)kCGImagePropertyGPSImgDirection];
    
            [GPSDictionary setObject:[NSNumber numberWithFloat:37.795]
                              forKey:(NSString*)kCGImagePropertyGPSDestLatitude];
    
            [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSDestLatitudeRef];
    
            [GPSDictionary setObject:[NSNumber numberWithFloat:122.410]
                              forKey:(NSString*)kCGImagePropertyGPSDestLongitude];
    
            [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSDestLongitudeRef];
    
            [EXIFDictionary setObject:@"[S.D.] kCGImagePropertyExifUserComment"
                               forKey:(NSString *)kCGImagePropertyExifUserComment];
    
            [EXIFDictionary setObject:[NSNumber numberWithFloat:69.999]
                               forKey:(NSString*)kCGImagePropertyExifSubjectDistance];
    
    
            //Add the modified Data back into the image’s metadata
            [metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
            [metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
            [metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary];
    
    
            CFStringRef UTI = CGImageSourceGetType(imgSource); //this is the type of image (e.g., public.jpeg)
    
            //this will be the data CGImageDestinationRef will write into
            NSMutableData *newImageData = [NSMutableData data];
    
            CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, UTI, 1, NULL);
    
            if(!destination)
                NSLog(@"***Could not create image destination ***");
    
            //add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
            CGImageDestinationAddImageFromSource(destination, imgSource, 0, (__bridge CFDictionaryRef) metadataAsMutable);
    
            //tell the destination to write the image data and metadata into our data object.
            //It will return false if something goes wrong
            BOOL success = NO;
            success = CGImageDestinationFinalize(destination);
    
            if(!success)
                NSLog(@"***Could not create data from image destination ***");
    
            CIImage *testImage = [CIImage imageWithData:newImageData];
            NSDictionary *propDict = [testImage properties];
            NSLog(@"Final properties %@", propDict);
    
        }];
    

    Which outputs this:

    Final properties info {
        ColorModel = RGB;
        DPIHeight = 72;
        DPIWidth = 72;
        Depth = 8;
        Orientation = 6;
        PixelHeight = 2448;
        PixelWidth = 3264;
        "{Exif}" =     {
            ApertureValue = "2.526069";
            BrightnessValue = "0.547474";
            ColorSpace = 1;
            ComponentsConfiguration =         (
                0,
                0,
                0,
                1
            );
            ExifVersion =         (
                2,
                2,
                1
            );
            ExposureMode = 0;
            ExposureProgram = 2;
            ExposureTime = "0.05";
            FNumber = "2.4";
            Flash = 16;
            FlashPixVersion =         (
                1,
                0
            );
            FocalLenIn35mmFilm = 35;
            FocalLength = "4.28";
            ISOSpeedRatings =         (
                320
            );
            MeteringMode = 5;
            PixelXDimension = 3264;
            PixelYDimension = 2448;
            SceneCaptureType = 0;
            SensingMethod = 2;
            ShutterSpeedValue = "4.321929";
            SubjectArea =         (
                1631,
                1223,
                881,
                881
            );
            SubjectDistance = "69.999";
            UserComment = "[S.D.] kCGImagePropertyExifUserComment";
            WhiteBalance = 0;
        };
        "{GPS}" =     {
            DateStamp = "2012:10:18";
            DestLatitude = "37.795";
            DestLatitudeRef = N;
            DestLongitude = "122.41";
            DestLongitudeRef = W;
            ImgDirection = 300;
            Latitude = "37.795";
            LatitudeRef = N;
            Longitude = "122.41";
            LongitudeRef = W;
        };
        "{JFIF}" =     {
            DensityUnit = 1;
            JFIFVersion =         (
                1,
                1
            );
            XDensity = 72;
            YDensity = 72;
        };
        "{TIFF}" =     {
            Orientation = 6;
            ResolutionUnit = 2;
            XResolution = 72;
            YResolution = 72;
            "_YCbCrPositioning" = 1;
        };
    }
    

    As you can see, all values are now properly embedded into the EXIF header and I’ve tested that this is correctly written with the JPG to the camera roll.

    Enjoy! 🙂

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

After countless headaches and time wasted I managed to get the AudioRecorder working for
While reading through countless answers on here I can't seem to find one that
I am a little confused, and after countless attempts and read several articles I
After solving countless problems with the hg-fast-export tool on Windows (from finicky python version
After adding Restkit to the Podfile : platform :ios dependency 'Facebook-iOS-SDK', '1.2' dependency 'RestKit',
Here's something I've been pondering after countless hours fixing JS to be cross-browser compatible
I have a Page Viewer webpart that displays /_layouts/google.htm and needs changing. I applied
I edited the question after David Hanak's answer (thanks btw!). He helped with the
After countless hours trying to style a QComboBox, I'm stuck with the top and
I'm struggling with some JavaScript code that I have used countless times across my

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.