1

I am debugging an app layout issue where I'm comparing thousands of screenshots of the application and checking for anomalies. I want to add some debugging information to the UIImage when it is saved to disk so I can compare them later as I read across all the written screenshots. I am currently looking at CGImageProperties which has good references online like https://ikyle.me/blog/2020/ios-metadata-from-file. Unfortunately, this never seems to work for me on my local iOS simulator (where I am running this code).

Screenshot code:

  UIGraphicsBeginImageContextWithOptions(element.size, NO, screen.scale);
  [view drawViewHierarchyInContext....];
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

So, now I am trying to add some properties to this image:

  NSData *imageData = UIImagePNGRepresentation(image);
  // NOTE: This can be any property that allows a long string.
  NSDictionary *prop = @{ (NSString *)kCGImagePropertyGPSLongitudeRef: @"E" };
  // Get source of the file.
  CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);
  CFStringRef UTI = CGImageSourceGetType(source);
  // Create empty data to be written to.
  NSMutableData *updatedData = [NSMutableData data];
  // Create a destination and add the source data with the properties.
  CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)updatedData, UTI, 1, NULL);
  CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef)[prop mutableCopy]);
  CGImageDestinationFinalize(destination);

  CFRelease(destination);
  CFRelease(source);
  
  UIImage *imageWithProperties = [UIImage updatedData];

At this point, I have an image that will hopefully have the new properties added to them. However, if I try to get the properties:

  CGImageSourceRef sourceForImageWithProperties = CGImageSourceCreateWithData((__bridge CFDataRef)UIImagePNGRepresentation(imageWithProperties), NULL);
  CFDictionaryRef imagePropertiesDict = CGImageSourceCopyPropertiesAtIndex(sourceForImageWithProperties, 0, NULL);
  NSLog(@"%@", (__bridge NSDictionary *)(imagePropertiesDict));

This unfortunately, has never worked for me even though most example seem to be the same as above. Properties invariably are:

{
    ColorModel = RGB;
    Depth = 8;
    HasAlpha = 1;
    PixelHeight = 132;
    PixelWidth = 1059;
    ProfileName = "sRGB IEC61966-2.1";
    "{Exif}" =     {
        ColorSpace = 1;
        PixelXDimension = 1059;
        PixelYDimension = 132;
    };
    "{PNG}" =     {
        Chromaticities =         (
            "0.3127",
            "0.329",
            "0.64",
            "0.33",
            "0.3",
            "0.6000000000000001",
            "0.15",
            "0.06"
        );
        Gamma = "0.45455";
        InterlaceType = 0;
        sRGBIntent = 0;
    };
}

I'd love to know what I am doing wrong here. I have also tried the following:

  • Writing the properties and saving the image to disk using NSFileManager and then trying to read back from the saved image.
  • Extracting the CGImage out from the UIImage using code similar to Converting CGImageRef to NSData and then adding the properties and then creating a new UIImage with this CGImage and getting the properties out from both the CGImage and UIImage. This has also had no major changes to the properties.
  • Trying to get the properties before UIGraphicsEndImageContext(), just to try.

Can anyone please try to explain what I am missing here? To repro, take the code above (get a UIImage in any way and then update the metadata). Does this method no longer work with Xcode 14 and iOS 16?

I just need to attach some data / metadata as an NSArray or an NSString to an image that's saved to disk. Note: associated objects will not work for me. Any other possible solutions would be appreciated.

gran_profaci
  • 8,087
  • 15
  • 66
  • 99
  • See https://stackoverflow.com/a/5294574/20287183 – HangarRash Dec 03 '22 at 16:01
  • Thanks, with that, I can see the new property as part of the data. However, I want to turn that data into a UIImage and save it. I cannot see the property on the UIImage though. – gran_profaci Dec 03 '22 at 20:00
  • As in this code does not have the new EXIF: ``` UIImage *image = [UIImage imageWithData:mutatedData]; CGImageSourceRef source0 = CGImageSourceCreateWithData((__bridge CFDataRef)UIImagePNGRepresentation(image), NULL); CFDictionaryRef imageProperties0 = CGImageSourceCopyPropertiesAtIndex(source0, 0, NULL); NSLog(@"%@", (__bridge NSDictionary *)(imageProperties0) ); ``` – gran_profaci Dec 03 '22 at 20:22
  • 1
    @gran_profaci - a ***`UIImage`*** does not have metadata. An image ***file*** (.png, .jpg, etc) *can* have metadata. You have to keep track of the data yourself. – DonMag Dec 05 '22 at 17:28

0 Answers0